1 /* ============================================================ 2 * 3 * This file is a part of digiKam project 4 * https://www.digikam.org 5 * 6 * Date : 2006-09-15 7 * Description : Exiv2 library interface 8 * Exiv2: https://www.exiv2.org 9 * Exif : https://www.exif.org/Exif2-2.PDF 10 * Iptc : https://www.iptc.org/std/IIM/4.1/specification/IIMV4.1.pdf 11 * Xmp : https://www.adobe.com/devnet/xmp/pdfs/xmp_specification.pdf 12 * https://www.iptc.org/std/Iptc4xmpCore/1.0/specification/Iptc4xmpCore_1.0-spec-XMPSchema_8.pdf 13 * Paper: www.metadataworkinggroup.com/pdf/mwg_guidance.pdf 14 * 15 * Copyright (C) 2006-2021 by Gilles Caulier <caulier dot gilles at gmail dot com> 16 * Copyright (C) 2006-2013 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 17 * 18 * This program is free software; you can redistribute it 19 * and/or modify it under the terms of the GNU General 20 * Public License as published by the Free Software Foundation; 21 * either version 2, or (at your option) 22 * any later version. 23 * 24 * This program is distributed in the hope that it will be useful, 25 * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 * GNU General Public License for more details. 28 * 29 * ============================================================ */ 30 31 #ifndef DIGIKAM_META_ENGINE_H 32 #define DIGIKAM_META_ENGINE_H 33 34 // QT includes 35 36 #include <QByteArray> 37 #include <QString> 38 #include <QDateTime> 39 #include <QMap> 40 #include <QSharedDataPointer> 41 #include <QStringList> 42 #include <QVariant> 43 #include <QRegExp> 44 #include <QUrl> 45 #include <QImage> 46 47 // Local includes 48 49 #include "metaengine_data.h" 50 #include "digikam_export.h" 51 52 namespace Digikam 53 { 54 55 // TODO: merge with DMetadata class. 56 57 class DIGIKAM_EXPORT MetaEngine 58 { 59 60 public: 61 62 /** 63 * The item metadata writing mode, between item file metadata and XMP sidecar file, depending on the context. 64 * @sa MetadataWritingMode(), metadataWritingMode() 65 */ 66 enum MetadataWritingMode 67 { 68 /// Write metadata to item file only. 69 WRITE_TO_FILE_ONLY = 0, 70 71 /// Write metadata to sidecar file only. 72 WRITE_TO_SIDECAR_ONLY = 1, 73 74 /// Write metadata to item and sidecar files. 75 WRITE_TO_SIDECAR_AND_FILE = 2, 76 77 /// Write metadata to sidecar file only for read only items such as RAW files for example. 78 WRITE_TO_SIDECAR_ONLY_FOR_READ_ONLY_FILES = 3 79 }; 80 81 /** 82 * The item color workspace values given by Exif metadata. 83 */ 84 enum ImageColorWorkSpace 85 { 86 WORKSPACE_UNSPECIFIED = 0, 87 WORKSPACE_SRGB = 1, 88 WORKSPACE_ADOBERGB = 2, 89 WORKSPACE_UNCALIBRATED = 65535 90 }; 91 92 /** 93 * The item orientation values given by Exif metadata. 94 */ 95 enum ImageOrientation 96 { 97 ORIENTATION_UNSPECIFIED = 0, 98 ORIENTATION_NORMAL = 1, 99 ORIENTATION_HFLIP = 2, 100 ORIENTATION_ROT_180 = 3, 101 ORIENTATION_VFLIP = 4, 102 ORIENTATION_ROT_90_HFLIP = 5, 103 ORIENTATION_ROT_90 = 6, 104 ORIENTATION_ROT_90_VFLIP = 7, 105 ORIENTATION_ROT_270 = 8 106 }; 107 108 /** 109 * Xmp tag types, used by setXmpTag, only first three types are used 110 */ 111 enum XmpTagType 112 { 113 NormalTag = 0, 114 ArrayBagTag = 1, 115 StructureTag = 2, 116 ArrayLangTag = 3, 117 ArraySeqTag = 4 118 }; 119 120 /** 121 * Metadata Backend used to populate information. 122 */ 123 enum Backend 124 { 125 Exiv2Backend = 0, ///< Default backend used by MetaEngine 126 LibRawBackend, ///< DMetadata only 127 LibHeifBackend, ///< DMetadata only 128 ImageMagickBackend, ///< DMetadata only 129 FFMpegBackend, ///< DMetadata only 130 NoBackend ///< No backend used (aka file cannot be read) 131 }; 132 133 /** 134 * A map used to store Tags Key and Tags Value. 135 */ 136 typedef QMap<QString, QString> MetaDataMap; 137 138 /** 139 * A map used to store a list of Alternative Language values. 140 * The map key is the language code following RFC3066 notation 141 * (like "fr-FR" for French), and the map value the text. 142 */ 143 typedef QMap<QString, QString> AltLangMap; 144 145 /** 146 * A map used to store Tags Key and a list of Tags properties : 147 * - name, 148 * - title, 149 * - description. 150 */ 151 typedef QMap<QString, QStringList> TagsMap; 152 153 public: 154 155 /** 156 * Standard constructor. 157 */ 158 MetaEngine(); 159 160 /** 161 * Constructor to load from parsed data. 162 */ 163 explicit MetaEngine(const MetaEngineData& data); 164 165 /** 166 * Contructor to Load Metadata from item file. 167 */ 168 explicit MetaEngine(const QString& filePath); 169 170 /** 171 * Standard destructor 172 */ 173 virtual ~MetaEngine(); 174 175 public: 176 177 //----------------------------------------------------------------- 178 /// @name Static methods 179 //@{ 180 181 /** 182 * Return true if Exiv2 library initialization is done properly. 183 * This method must be called before using libMetaEngine with multithreading. 184 * It initialize several non re-entrancy code from Adobe XMP SDK, and register 185 * a function to cleanup automatically all XMP SDK memory allocation. 186 * See Bug #166424 for details. 187 */ 188 static bool initializeExiv2(); 189 190 /** 191 * Return true if Exiv2 library is compiled with Xmp metadata support. 192 */ 193 static bool supportXmp(); 194 195 /** 196 * Return true if library support Base Media File Format (aka CR3, HEIF, HEIC, and AVIF). 197 * Note: use this function only after to call initializeExiv2(), else false will aways returned. 198 * The function return true only if Exiv2 >= 0.27.4 compiled with BMFF support. 199 */ 200 static bool supportBmff(); 201 202 /** 203 * Return true if library can write metadata to typeMime file format. 204 */ 205 static bool supportMetadataWriting(const QString& typeMime); 206 207 /** 208 * Return a string version of Exiv2 release in format "major.minor.patch" 209 */ 210 static QString Exiv2Version(); 211 212 //@} 213 214 //----------------------------------------------------------------- 215 /// @name General methods 216 //@{ 217 218 MetaEngineData data() const; 219 void setData(const MetaEngineData& data); 220 221 /** 222 * Load all metadata (Exif, Iptc, Xmp, and JFIF Comments) from a byte array. 223 * Return true if metadata have been loaded successfully from item data. 224 */ 225 bool loadFromData(const QByteArray& imgData); 226 227 /** 228 * Return 'true' if metadata container in memory as no Comments, Exif, Iptc, and Xmp. 229 */ 230 bool isEmpty() const; 231 232 /** 233 * Returns the pixel size of the current item. This information is read from the file, 234 * not from the metadata. The returned QSize is valid if the MetaEngine object was _constructed_ 235 * by reading a file or item data; the information is not available when the object 236 * was created from MetaEngineData. 237 * Note that in the Exif or XMP metadata, there may be fields describing the item size. 238 * These fields are not accessed by this method. 239 * When replacing the metadata with setData(), the metadata may change; this information 240 * always keeps referring to the file it was initially read from. 241 */ 242 QSize getPixelSize() const; 243 244 /** 245 * Returns the mime type of this item. The information is read from the file; 246 * see the docs for getPixelSize() to know when it is available. 247 */ 248 QString getMimeType() const; 249 250 /** 251 * Enable or disable writing metadata operations to RAW tiff based files. 252 * It requires Exiv2 0.18. By default RAW files are untouched. 253 */ 254 void setWriteRawFiles(const bool on); 255 256 /** 257 * Return true if writing metadata operations on RAW tiff based files is enabled. 258 * It's require at least Exiv2 0.18. 259 */ 260 bool writeRawFiles() const; 261 262 /** 263 * Enable or disable writing metadata operations to DNG files. 264 */ 265 void setWriteDngFiles(const bool on); 266 267 /** 268 * Return true if writing metadata operations on DNG files is enabled. 269 */ 270 bool writeDngFiles() const; 271 272 /** 273 * Enable or disable using XMP sidecar for reading metadata. 274 */ 275 void setUseXMPSidecar4Reading(const bool on); 276 277 /** 278 * Return true if using XMP sidecar for reading metadata is enabled. 279 */ 280 bool useXMPSidecar4Reading() const; 281 282 /** 283 * Enable or disable using compatible file name for sidecar files. 284 */ 285 void setUseCompatibleFileName(const bool on); 286 287 /** 288 * Return true if using compatible file name for sidecar files. 289 */ 290 bool useCompatibleFileName() const; 291 292 /** 293 * Set metadata writing mode. 294 * @param mode Metadata writing mode as defined by the #MetadataWritingMode enum. 295 * @sa MetadataWritingMode, metadataWritingMode() 296 */ 297 void setMetadataWritingMode(const int mode); 298 299 /** 300 * Return the metadata writing mode. 301 * @returns Metadata writing mode as defined by the #MetadataWritingMode enum. 302 * @sa MetadataWritingMode, setMetadataWritingMode() 303 */ 304 int metadataWritingMode() const; 305 306 /** 307 * Enable or disable file timestamp updating when metadata are saved. 308 * By default files timestamp are untouched. 309 */ 310 void setUpdateFileTimeStamp(bool on); 311 312 /** 313 * Return true if file timestamp is updated when metadata are saved. 314 */ 315 bool updateFileTimeStamp() const; 316 317 //@} 318 319 //------------------------------------------------------------------- 320 /// @name File I/O methods 321 //@{ 322 323 /** 324 * Set the file path of current item. 325 */ 326 void setFilePath(const QString& path); 327 328 /** 329 * Return the file path of current item. 330 */ 331 QString getFilePath() const; 332 333 /** 334 * Return the XMP Sidecar file path for a item file path. 335 * If item file path do not include a file name or is empty, this function return a null string. 336 */ 337 static QString sidecarFilePathForFile(const QString& path, bool useLR = false); 338 339 /** 340 * Like sidecarFilePathForFile(), but works for local file path. 341 */ 342 static QString sidecarPath(const QString& path); 343 344 /** 345 * Like sidecarFilePathForFile(), but works for remote URLs. 346 */ 347 static QUrl sidecarUrl(const QUrl& url); 348 349 /** 350 * Gives a file url for a local path. 351 */ 352 static QUrl sidecarUrl(const QString& path); 353 354 /** 355 * Performs a QFileInfo based check if the given local file has a sidecar. 356 */ 357 static bool hasSidecar(const QString& path); 358 359 /** 360 * Return a string of backend name used to parse metadata from file. 361 * See Backend enum for details. 362 */ 363 static QString backendName(Backend t); 364 365 /** 366 * Load all metadata (Exif, Iptc, Xmp, and JFIF Comments) from a picture (JPEG, RAW, TIFF, PNG, 367 * DNG, etc...). Return true if metadata have been loaded successfully from file. 368 * If backend is non null, return the backend used to populate metadata (Exiv2). 369 * See Backend enum for details. 370 */ 371 bool load(const QString& filePath, Backend* backend = nullptr); 372 373 /** 374 * Load metadata from a sidecar file and merge. 375 * Return true if metadata have been loaded successfully from file. 376 */ 377 bool loadFromSidecarAndMerge(const QString& filePath); 378 379 /** 380 * Save all metadata to a file. This one can be different than original picture to perform 381 * transfert operation Return true if metadata have been saved into file. 382 */ 383 bool save(const QString& filePath, bool setVersion = false) const; 384 385 /** 386 * The same than save() method, but it apply on current item. Return true if metadata 387 * have been saved into file. 388 */ 389 bool applyChanges(bool setVersion = false) const; 390 391 /** 392 * List changed tags compared to original file contents and export result to 393 * a temporary EXV file container. 394 * 'exvTmpFile' is the path to the temporary EXV container to create. 395 * 'removedTags' is populated with the list of tags removed. 396 */ 397 bool exportChanges(const QString& exvTmpFile, QStringList& removedTags) const; 398 399 //@} 400 401 //------------------------------------------------------------------- 402 /// @name Metadata item information manipulation methods 403 //@{ 404 405 /** 406 * Set Program name and program version in Exif and Iptc Metadata. Return true if information 407 * have been changed in metadata. 408 */ 409 bool setItemProgramId(const QString& program, const QString& version) const; 410 411 /** 412 * Return the size of item in pixels using Exif tags. Return a null dimension if size cannot 413 * be found. 414 */ 415 QSize getItemDimensions() const; 416 417 /** 418 * Set the size of item in pixels in Exif tags. Return true if size have been changed 419 * in metadata. 420 */ 421 bool setItemDimensions(const QSize& size) const; 422 423 /** 424 * Return the item orientation set in Exif metadata. The makernotes of item are also parsed to 425 * get this information. See ImageOrientation values for details. 426 */ 427 MetaEngine::ImageOrientation getItemOrientation() const; 428 429 /** 430 * Set the Exif orientation tag of item. See ImageOrientation values for details 431 * Return true if orientation have been changed in metadata. 432 */ 433 bool setItemOrientation(ImageOrientation orientation) const; 434 435 /** 436 * Return the item color-space set in Exif metadata. The makernotes of item are also parsed to 437 * get this information. See ImageColorWorkSpace values for details. 438 */ 439 MetaEngine::ImageColorWorkSpace getItemColorWorkSpace() const; 440 441 /** 442 * Set the Exif color-space tag of item. See ImageColorWorkSpace values for details 443 * Return true if work-space have been changed in metadata. 444 */ 445 bool setItemColorWorkSpace(ImageColorWorkSpace workspace) const; 446 447 /** 448 * Return the time stamp of item. Exif information are check in first, IPTC in second 449 * if item don't have Exif information. If no time stamp is found, a null date is returned. 450 */ 451 QDateTime getItemDateTime() const; 452 453 /** 454 * Set the Exif and Iptc time stamp. If 'setDateTimeDigitized' parameter is true, the 'Digitalized' 455 * time stamp is set, else only 'Created' time stamp is set. 456 */ 457 bool setImageDateTime(const QDateTime& dateTime, bool setDateTimeDigitized = false) const; 458 459 /** 460 * Return the digitization time stamp of the item. First Exif information is checked, then IPTC. 461 * If no digitization time stamp is found, getItemDateTime() is called if fallbackToCreationTime 462 * is true, or a null QDateTime is returned if fallbackToCreationTime is false. 463 */ 464 QDateTime getDigitizationDateTime(bool fallbackToCreationTime = false) const; 465 466 /** 467 * Return a QImage copy of Iptc preview image. Return a null item if preview cannot 468 * be found. 469 */ 470 bool getItemPreview(QImage& preview) const; 471 472 /** 473 * Set the Iptc preview image. The thumbnail item must have the right size before (64Kb max 474 * with JPEG file, else 256Kb). Look Iptc specification for details. Return true if preview 475 * have been changed in metadata. 476 * Re-implement this method if you want to use another item file format than JPEG to 477 * save preview. 478 */ 479 bool setItemPreview(const QImage& preview) const; 480 481 //@} 482 483 //----------------------------------------------------------------- 484 /// @name Comments manipulation methods 485 //@{ 486 487 /** 488 * Return 'true' if Comments can be written in file. 489 */ 490 static bool canWriteComment(const QString& filePath); 491 492 /** 493 * Return 'true' if metadata container in memory as Comments. 494 */ 495 bool hasComments() const; 496 497 /** 498 * Clear the Comments metadata container in memory. 499 */ 500 bool clearComments() const; 501 502 /** 503 * Return a Qt byte array copy of Comments container get from current item. 504 * Comments are JFIF section of JPEG images. Look Exiv2 API for more information. 505 * Return a null Qt byte array if there is no Comments metadata in memory. 506 */ 507 QByteArray getComments() const; 508 509 /** 510 * Return a Qt string object of Comments from current item decoded using 511 * the 'detectEncodingAndDecode()' method. Return a null string if there is no 512 * Comments metadata available. 513 */ 514 QString getCommentsDecoded() const; 515 516 /** 517 * Set the Comments data using a Qt byte array. Return true if Comments metadata 518 * have been changed in memory. 519 */ 520 bool setComments(const QByteArray& data) const; 521 522 /** 523 * Language Alternative autodetection. Return a QString without language alternative 524 * header. Header is saved into 'lang'. If no language alternative is founf, value is returned 525 * as well and 'lang' is set to a null string. 526 */ 527 static QString detectLanguageAlt(const QString& value, QString& lang); 528 529 //@} 530 531 //----------------------------------------------------------------- 532 /// @name Exif manipulation methods 533 //@{ 534 535 /** 536 * Return a map of all standard Exif tags supported by Exiv2. 537 */ 538 TagsMap getStdExifTagsList() const; 539 540 /** 541 * Return a map of all non-standard Exif tags (makernotes) supported by Exiv2. 542 */ 543 TagsMap getMakernoteTagsList() const; 544 545 /** 546 * Return 'true' if Exif can be written in file. 547 */ 548 static bool canWriteExif(const QString& filePath); 549 550 /** 551 * Return 'true' if metadata container in memory as Exif. 552 */ 553 bool hasExif() const; 554 555 /** 556 * Clear the Exif metadata container in memory. 557 */ 558 bool clearExif() const; 559 560 /** 561 * Returns the exif data encoded to a QByteArray in a form suitable 562 * for storage in a JPEG image. 563 * Note that this encoding is a lossy operation. 564 * 565 * Set true 'addExifHeader' parameter to add an Exif header to Exif metadata. 566 * Returns a null Qt byte array if there is no Exif metadata in memory. 567 */ 568 QByteArray getExifEncoded(bool addExifHeader = false) const; 569 570 /** 571 * Set the Exif data using a Qt byte array. Return true if Exif metadata 572 * have been changed in memory. 573 */ 574 bool setExif(const QByteArray& data) const; 575 576 /** 577 * Return a QImage copy of Exif thumbnail image. Return a null image if thumbnail cannot 578 * be found. The 'fixOrientation' parameter will rotate automatically the thumbnail if Exif 579 * orientation tags information are attached with thumbnail. 580 */ 581 QImage getExifThumbnail(bool fixOrientation) const; 582 583 /** 584 * Fix orientation of a QImage image accordingly with Exif orientation tag. 585 * Return true if image is rotated, else false. 586 */ 587 bool rotateExifQImage(QImage& image, ImageOrientation orientation) const; 588 589 /** 590 * Set the Exif Thumbnail image. The thumbnail image must have the right dimensions before. 591 * Look Exif specification for details. Return true if thumbnail have been changed in metadata. 592 */ 593 bool setExifThumbnail(const QImage& thumb) const; 594 595 /** 596 * Remove the Exif Thumbnail from the item 597 */ 598 bool removeExifThumbnail() const; 599 600 /** 601 * Adds a JPEG thumbnail to a TIFF images. Use this instead of setExifThumbnail for TIFF images. 602 */ 603 bool setTiffThumbnail(const QImage& thumb) const; 604 605 /** 606 * Return a QString copy of Exif user comments. Return a null string if user comments cannot 607 * be found. 608 */ 609 QString getExifComment(bool readDescription = true) const; 610 611 /** 612 * Set the Exif user comments from item. Look Exif specification for more details about this tag. 613 * Return true if Exif user comments have been changed in metadata. 614 */ 615 bool setExifComment(const QString& comment, bool writeDescription = true) const; 616 617 /** 618 * Get an Exif tags content like a string. If 'escapeCR' parameter is true, the CR characters 619 * will be removed. If Exif tag cannot be found a null string is returned. 620 */ 621 QString getExifTagString(const char* exifTagName, bool escapeCR = true) const; 622 623 /** 624 * Set an Exif tag content using a string. Return true if tag is set successfully. 625 */ 626 bool setExifTagString(const char* exifTagName, const QString& value) const; 627 628 /** 629 * Get an Exif tag content like a long value. Return true if Exif tag be found. 630 */ 631 bool getExifTagLong(const char* exifTagName, long &val) const; 632 633 /** 634 * Get an Exif tag content like a long value. Return true if Exif tag be found. 635 */ 636 bool getExifTagLong(const char* exifTagName, long &val, int component) const; 637 638 /** 639 * Set an Exif tag content using a long value. Return true if tag is set successfully. 640 */ 641 bool setExifTagLong(const char* exifTagName, long val) const; 642 643 /** 644 * Get the 'component' index of an Exif tags content like a rational value. 645 * 'num' and 'den' are the numerator and the denominator of the rational value. 646 * Return true if Exif tag be found. 647 */ 648 bool getExifTagRational(const char* exifTagName, long int& num, long int& den, int component = 0) const; 649 650 /** 651 * Set an Exif tag content using a rational value. 652 * 'num' and 'den' are the numerator and the denominator of the rational value. 653 * Return true if tag is set successfully. 654 */ 655 bool setExifTagRational(const char* exifTagName, long int num, long int den) const; 656 657 /** 658 * Get an Exif tag content like a bytes array. Return an empty bytes array if Exif 659 * tag cannot be found. 660 */ 661 QByteArray getExifTagData(const char* exifTagName) const; 662 663 /** 664 * Set an Exif tag content using a bytes array. Return true if tag is set successfully. 665 */ 666 bool setExifTagData(const char* exifTagName, const QByteArray& data) const; 667 668 /** 669 * Get an Exif tags content as a QVariant. Returns a null QVariant if the Exif 670 * tag cannot be found. 671 * For string and integer values the matching QVariant types will be used, 672 * for date and time values QVariant::DateTime. 673 * Rationals will be returned as QVariant::List with two integer QVariants (numerator, denominator) 674 * if rationalAsListOfInts is true, as double if rationalAsListOfInts is false. 675 * An exif tag of numerical type may contain more than one value; set component to the desired index. 676 */ 677 QVariant getExifTagVariant(const char* exifTagName, bool rationalAsListOfInts = true, 678 bool escapeCR = true, int component = 0) const; 679 680 /** 681 * Set an Exif tag content using a QVariant. Returns true if tag is set successfully. 682 * All types described for the getExifTagVariant() method are supported. 683 * Calling with a QVariant of type ByteArray is equivalent to calling setExifTagData. 684 * For the meaning of rationalWantSmallDenominator, see the documentation of the convertToRational methods. 685 * Setting a value with multiple components is currently not supported. 686 */ 687 bool setExifTagVariant(const char* exifTagName, const QVariant& data, 688 bool rationalWantSmallDenominator = true) const; 689 690 /** 691 * Remove the Exif tag 'exifTagName' from Exif metadata. Return true if tag is 692 * removed successfully or if no tag was present. 693 */ 694 bool removeExifTag(const char* exifTagName) const; 695 696 /** 697 * Return the Exif Tag title or a null string. 698 */ 699 QString getExifTagTitle(const char* exifTagName); 700 701 /** 702 * Return the Exif Tag description or a null string. 703 */ 704 QString getExifTagDescription(const char* exifTagName); 705 706 /** 707 * Takes a QVariant value as it could have been retrieved by getExifTagVariant with the given exifTagName, 708 * and returns its value properly converted to a string (including translations from Exiv2). 709 * This is equivalent to calling getExifTagString directly. 710 * If escapeCR is true CR characters will be removed from the result. 711 */ 712 QString createExifUserStringFromValue(const char* exifTagName, const QVariant& val, bool escapeCR = true); 713 714 /** 715 * Return a map of Exif tags name/value found in metadata sorted by 716 * Exif keys given by 'exifKeysFilter'. 717 * 718 * 'exifKeysFilter' is a QStringList of Exif keys. 719 * For example, if you use the string list given below: 720 * 721 * "Iop" 722 * "Thumbnail" 723 * "Image" 724 * "Photo" 725 * 726 * List can be empty to not filter output. 727 * 728 * ... this method will return a map of all Exif tags which : 729 * 730 * - include "Iop", or "Thumbnail", or "Image", or "Photo" in the Exif tag keys 731 * if 'inverSelection' is false. 732 * - not include "Iop", or "Thumbnail", or "Image", or "Photo" in the Exif tag keys 733 * if 'inverSelection' is true. 734 * if 'extractBinary" is true, tags with undefined types of data are extracted (default), 735 * else contents is replaced by "Binary data ... bytes". Take a care as large binary data as 736 * origianl RAW data from DNG container can be huge and listing Exif tags from GUI can take a while. 737 */ 738 MetaEngine::MetaDataMap getExifTagsDataList(const QStringList& exifKeysFilter = QStringList(), 739 bool invertSelection = false, 740 bool extractBinary = true) const; 741 742 //@} 743 744 //------------------------------------------------------------- 745 /// @name IPTC manipulation methods 746 //@{ 747 748 /** 749 * Return a map of all standard Iptc tags supported by Exiv2. 750 */ 751 MetaEngine::TagsMap getIptcTagsList() const; 752 753 /** 754 * Return 'true' if Iptc can be written in file. 755 */ 756 static bool canWriteIptc(const QString& filePath); 757 758 /** 759 * Return 'true' if metadata container in memory as Iptc. 760 */ 761 bool hasIptc() const; 762 763 /** 764 * Clear the Iptc metadata container in memory. 765 */ 766 bool clearIptc() const; 767 768 /** 769 * Return a Qt byte array copy of Iptc container get from current item. 770 * Set true 'addIrbHeader' parameter to add an Irb header to Iptc metadata. 771 * Return a null Qt byte array if there is no Iptc metadata in memory. 772 */ 773 QByteArray getIptc(bool addIrbHeader = false) const; 774 775 /** 776 * Set the Iptc data using a Qt byte array. Return true if Iptc metadata 777 * have been changed in memory. 778 */ 779 bool setIptc(const QByteArray& data) const; 780 781 /** 782 * Get an Iptc tag content like a string. If 'escapeCR' parameter is true, the CR characters 783 * will be removed. If Iptc tag cannot be found a null string is returned. 784 */ 785 QString getIptcTagString(const char* iptcTagName, bool escapeCR = true) const; 786 787 /** 788 * Set an Iptc tag content using a string. Return true if tag is set successfully. 789 */ 790 bool setIptcTagString(const char* iptcTagName, const QString& value) const; 791 792 /** 793 * Returns a strings list with of multiple Iptc tags from the item. Return an empty list if no tag is found. 794 * Get the values of all IPTC tags with the given tag name in a string list. 795 * (In Iptc, there can be multiple tags with the same name) 796 * If the 'escapeCR' parameter is true, the CR characters 797 * will be removed. 798 * If no tag can be found an empty list is returned. 799 */ 800 QStringList getIptcTagsStringList(const char* iptcTagName, bool escapeCR = true) const; 801 802 /** 803 * Set multiple Iptc tags contents using a strings list. 'maxSize' is the max characters size 804 * of one entry. Return true if all tags have been set successfully. 805 */ 806 bool setIptcTagsStringList(const char* iptcTagName, int maxSize, 807 const QStringList& oldValues, const QStringList& newValues) const; 808 809 /** 810 * Get an Iptc tag content as a bytes array. Return an empty bytes array if Iptc 811 * tag cannot be found. 812 */ 813 QByteArray getIptcTagData(const char* iptcTagName) const; 814 815 /** 816 * Set an Iptc tag content using a bytes array. Return true if tag is set successfully. 817 */ 818 bool setIptcTagData(const char* iptcTagName, const QByteArray& data) const; 819 820 /** 821 * Remove the all instance of Iptc tags 'iptcTagName' from Iptc metadata. Return true if all 822 * tags have been removed successfully (or none were present). 823 */ 824 bool removeIptcTag(const char* iptcTagName) const; 825 826 /** 827 * Return the Iptc Tag title or a null string. 828 */ 829 QString getIptcTagTitle(const char* iptcTagName); 830 831 /** 832 * Return the Iptc Tag description or a null string. 833 */ 834 QString getIptcTagDescription(const char* iptcTagName); 835 836 /** 837 * Return a map of Iptc tags name/value found in metadata sorted by 838 * Iptc keys given by 'iptcKeysFilter'. 839 * 840 * 'iptcKeysFilter' is a QStringList of Iptc keys. 841 * For example, if you use the string list given below: 842 * 843 * "Envelope" 844 * "Application2" 845 * 846 * List can be empty to not filter output. 847 * 848 * ... this method will return a map of all Iptc tags which : 849 * 850 * - include "Envelope", or "Application2" in the Iptc tag keys 851 * if 'inverSelection' is false. 852 * - not include "Envelope", or "Application2" in the Iptc tag keys 853 * if 'inverSelection' is true. 854 */ 855 MetaEngine::MetaDataMap getIptcTagsDataList(const QStringList& iptcKeysFilter = QStringList(), 856 bool invertSelection = false) const; 857 858 /** 859 * Return a strings list of Iptc keywords from item. Return an empty list if no keyword are set. 860 */ 861 QStringList getIptcKeywords() const; 862 863 /** 864 * Set Iptc keywords using a list of strings defined by 'newKeywords' parameter. Use 'getImageKeywords()' 865 * method to set 'oldKeywords' parameter with existing keywords from item. The method will compare 866 * all new keywords with all old keywords to prevent duplicate entries in item. Return true if keywords 867 * have been changed in metadata. 868 */ 869 bool setIptcKeywords(const QStringList& oldKeywords, const QStringList& newKeywords) const; 870 871 /** 872 * Return a strings list of Iptc subjects from item. Return an empty list if no subject are set. 873 */ 874 QStringList getIptcSubjects() const; 875 876 /** 877 * Set Iptc subjects using a list of strings defined by 'newSubjects' parameter. Use 'getImageSubjects()' 878 * method to set 'oldSubjects' parameter with existing subjects from item. The method will compare 879 * all new subjects with all old subjects to prevent duplicate entries in item. Return true if subjects 880 * have been changed in metadata. 881 */ 882 bool setIptcSubjects(const QStringList& oldSubjects, const QStringList& newSubjects) const; 883 884 /** 885 * Return a strings list of Iptc sub-categories from item. Return an empty list if no sub-category 886 * are set. 887 */ 888 QStringList getIptcSubCategories() const; 889 890 /** 891 * Set Iptc sub-categories using a list of strings defined by 'newSubCategories' parameter. Use 892 * 'getImageSubCategories()' method to set 'oldSubCategories' parameter with existing sub-categories 893 * from item. The method will compare all new sub-categories with all old sub-categories to prevent 894 * duplicate entries in item. Return true if sub-categories have been changed in metadata. 895 */ 896 bool setIptcSubCategories(const QStringList& oldSubCategories, const QStringList& newSubCategories) const; 897 898 //@} 899 900 //------------------------------------------------------------ 901 /// @name XMP manipulation methods 902 //@{ 903 904 /** 905 * Return a map of all standard Xmp tags supported by Exiv2. 906 */ 907 MetaEngine::TagsMap getXmpTagsList() const; 908 909 /** 910 * Return 'true' if Xmp can be written in file. 911 */ 912 static bool canWriteXmp(const QString& filePath); 913 914 /** 915 * Return 'true' if metadata container in memory as Xmp. 916 */ 917 bool hasXmp() const; 918 919 /** 920 * Clear the Xmp metadata container in memory. 921 */ 922 bool clearXmp() const; 923 924 /** 925 * Return a Qt byte array copy of XMp container get from current item. 926 * Return a null Qt byte array if there is no Xmp metadata in memory. 927 */ 928 QByteArray getXmp() const; 929 930 /** 931 * Set the Xmp data using a Qt byte array. Return true if Xmp metadata 932 * have been changed in memory. 933 */ 934 bool setXmp(const QByteArray& data) const; 935 936 /** 937 * Get a Xmp tag content like a string. If 'escapeCR' parameter is true, the CR characters 938 * will be removed. If Xmp tag cannot be found a null string is returned. 939 */ 940 QString getXmpTagString(const char* xmpTagName, bool escapeCR = true) const; 941 942 /** 943 * Set a Xmp tag content using a string. Return true if tag is set successfully. 944 */ 945 bool setXmpTagString(const char* xmpTagName, const QString& value) const; 946 947 /** 948 * Set a Xmp tag with a specific type. Return true if tag is set successfully. 949 * This method only accept NormalTag, ArrayBagTag and StructureTag. 950 * Other XmpTagTypes do nothing 951 */ 952 bool setXmpTagString(const char* xmpTagName, const QString& value, 953 XmpTagType type) const; 954 955 /** 956 * Return the Xmp Tag title or a null string. 957 */ 958 QString getXmpTagTitle(const char* xmpTagName); 959 960 /** 961 * Return the Xmp Tag description or a null string. 962 */ 963 QString getXmpTagDescription(const char* xmpTagName); 964 965 /** 966 * Return a map of Xmp tags name/value found in metadata sorted by 967 * Xmp keys given by 'xmpKeysFilter'. 968 * 969 * 'xmpKeysFilter' is a QStringList of Xmp keys. 970 * For example, if you use the string list given below: 971 * 972 * "dc" // Dubling Core schema. 973 * "xmp" // Standard Xmp schema. 974 * 975 * List can be empty to not filter output. 976 * 977 * ... this method will return a map of all Xmp tags which : 978 * 979 * - include "dc", or "xmp" in the Xmp tag keys 980 * if 'inverSelection' is false. 981 * - not include "dc", or "xmp" in the Xmp tag keys 982 * if 'inverSelection' is true. 983 */ 984 MetaEngine::MetaDataMap getXmpTagsDataList(const QStringList& xmpKeysFilter = QStringList(), 985 bool invertSelection = false) const; 986 987 /** 988 * Get all redondant Alternative Language Xmp tags content like a map. 989 * See AltLangMap class description for details. 990 * If 'escapeCR' parameter is true, the CR characters will be removed from strings. 991 * If Xmp tag cannot be found a null string list is returned. 992 */ 993 MetaEngine::AltLangMap getXmpTagStringListLangAlt(const char* xmpTagName, 994 bool escapeCR = true) const; 995 996 /** 997 * Set an Alternative Language Xmp tag content using a map. See AltLangMap class 998 * description for details. If tag already exist, it will be removed before. 999 * Return true if tag is set successfully. 1000 */ 1001 bool setXmpTagStringListLangAlt(const char* xmpTagName, const MetaEngine::AltLangMap& values) const; 1002 1003 /** 1004 * Get a Xmp tag content like a string set with an alternative language 1005 * header 'langAlt' (like "fr-FR" for French - RFC3066 notation) 1006 * If 'escapeCR' parameter is true, the CR characters will be removed. 1007 * If Xmp tag cannot be found a null string is returned. 1008 */ 1009 QString getXmpTagStringLangAlt(const char* xmpTagName, const QString& langAlt, bool escapeCR) const; 1010 1011 /** 1012 * Set a Xmp tag content using a string with an alternative language header. 'langAlt' contain the 1013 * language alternative information (like "fr-FR" for French - RFC3066 notation) or is null to 1014 * set alternative language to default settings ("x-default"). 1015 * Return true if tag is set successfully. 1016 */ 1017 bool setXmpTagStringLangAlt(const char* xmpTagName, const QString& value, 1018 const QString& langAlt) const; 1019 1020 /** 1021 * Get a Xmp tag content like a sequence of strings. If 'escapeCR' parameter is true, the CR characters 1022 * will be removed from strings. If Xmp tag cannot be found a null string list is returned. 1023 */ 1024 QStringList getXmpTagStringSeq(const char* xmpTagName, bool escapeCR = true) const; 1025 1026 /** 1027 * Set a Xmp tag content using the sequence of strings 'seq'. 1028 * Return true if tag is set successfully. 1029 */ 1030 bool setXmpTagStringSeq(const char* xmpTagName, const QStringList& seq) const; 1031 1032 /** 1033 * Get a Xmp tag content like a bag of strings. If 'escapeCR' parameter is true, the CR characters 1034 * will be removed from strings. If Xmp tag cannot be found a null string list is returned. 1035 */ 1036 QStringList getXmpTagStringBag(const char* xmpTagName, bool escapeCR) const; 1037 1038 /** 1039 * Set a Xmp tag content using the bag of strings 'bag'. 1040 * Return true if tag is set successfully. 1041 */ 1042 bool setXmpTagStringBag(const char* xmpTagName, const QStringList& bag) const; 1043 1044 /** 1045 * Set an Xmp tag content using a list of strings defined by the 'entriesToAdd' parameter. 1046 * The existing entries are preserved. The method will compare 1047 * all new with all already existing entries to prevent duplicates in the item. 1048 * Return true if the entries have been added to metadata. 1049 */ 1050 bool addToXmpTagStringBag(const char* xmpTagName, const QStringList& entriesToAdd) const; 1051 1052 /** 1053 * Remove those Xmp tag entries that are listed in entriesToRemove from the entries in metadata. 1054 * Return true if tag entries are no longer contained in metadata. 1055 * All other entries are preserved. 1056 */ 1057 bool removeFromXmpTagStringBag(const char* xmpTagName, const QStringList& entriesToRemove) const; 1058 1059 /** 1060 * Get an Xmp tag content as a QVariant. Returns a null QVariant if the Xmp 1061 * tag cannot be found. 1062 * For string and integer values the matching QVariant types will be used, 1063 * for date and time values QVariant::DateTime. 1064 * Rationals will be returned as QVariant::List with two integer QVariants (numerator, denominator) 1065 * if rationalAsListOfInts is true, as double if rationalAsListOfInts is false. 1066 * Arrays (ordered, unordered, alternative) are returned as type StringList. 1067 * LangAlt values will have type Map (QMap<QString, QVariant>) with the language 1068 * code as key and the contents as value, of type String. 1069 */ 1070 QVariant getXmpTagVariant(const char* xmpTagName, bool rationalAsListOfInts = true, bool stringEscapeCR = true) const; 1071 1072 /** 1073 * Return a strings list of Xmp keywords from item. Return an empty list if no keyword are set. 1074 */ 1075 QStringList getXmpKeywords() const; 1076 1077 /** 1078 * Set Xmp keywords using a list of strings defined by 'newKeywords' parameter. 1079 * The existing keywords from item are preserved. The method will compare 1080 * all new keywords with all already existing keywords to prevent duplicate entries in item. 1081 * Return true if keywords have been changed in metadata. 1082 */ 1083 bool setXmpKeywords(const QStringList& newKeywords) const; 1084 1085 /** 1086 * Remove those Xmp keywords that are listed in keywordsToRemove from the keywords in metadata. 1087 * Return true if keywords are no longer contained in metadata. 1088 */ 1089 bool removeXmpKeywords(const QStringList& keywordsToRemove); 1090 1091 /** 1092 * Return a strings list of Xmp subjects from item. Return an empty list if no subject are set. 1093 */ 1094 QStringList getXmpSubjects() const; 1095 1096 /** 1097 * Set Xmp subjects using a list of strings defined by 'newSubjects' parameter. 1098 * The existing subjects from item are preserved. The method will compare 1099 * all new subject with all already existing subject to prevent duplicate entries in item. 1100 * Return true if subjects have been changed in metadata. 1101 */ 1102 bool setXmpSubjects(const QStringList& newSubjects) const; 1103 1104 /** 1105 * Remove those Xmp subjects that are listed in subjectsToRemove from the subjects in metadata. 1106 * Return true if subjects are no longer contained in metadata. 1107 */ 1108 bool removeXmpSubjects(const QStringList& subjectsToRemove); 1109 1110 /** 1111 * Return a strings list of Xmp sub-categories from item. Return an empty list if no sub-category 1112 * are set. 1113 */ 1114 QStringList getXmpSubCategories() const; 1115 1116 /** 1117 * Set Xmp sub-categories using a list of strings defined by 'newSubCategories' parameter. 1118 * The existing sub-categories from item are preserved. The method will compare 1119 * all new sub-categories with all already existing sub-categories to prevent duplicate entries in item. 1120 * Return true if sub-categories have been changed in metadata. 1121 */ 1122 bool setXmpSubCategories(const QStringList& newSubCategories) const; 1123 1124 /** 1125 * Remove those Xmp sub-categories that are listed in categoriesToRemove from the sub-categories in metadata. 1126 * Return true if subjects are no longer contained in metadata. 1127 */ 1128 bool removeXmpSubCategories(const QStringList& categoriesToRemove); 1129 1130 /** 1131 * Remove the Xmp tag 'xmpTagName' from Xmp metadata. Return true if tag is 1132 * removed successfully or if no tag was present. 1133 */ 1134 bool removeXmpTag(const char* xmpTagName, bool family = false) const; 1135 1136 /** 1137 * Register a namespace which Exiv2 doesn't know yet. This is only needed 1138 * when new Xmp properties are added manually. 'uri' is the namespace url and 'prefix' the 1139 * string used to construct new Xmp key (ex. "Xmp.digiKam.tagList"). 1140 * NOTE: If the Xmp metadata is read from an item, namespaces are decoded and registered 1141 * by Exiv2 at the same time. 1142 */ 1143 static bool registerXmpNameSpace(const QString& uri, const QString& prefix); 1144 1145 /** 1146 * Unregister a previously registered custom namespace 1147 */ 1148 static bool unregisterXmpNameSpace(const QString& uri); 1149 1150 //@} 1151 1152 //------------------------------------------------------------ 1153 /// @name GPS manipulation methods 1154 //@{ 1155 1156 /** 1157 * Make sure all static required GPS EXIF and XMP tags exist 1158 */ 1159 bool initializeGPSInfo(); 1160 1161 /** 1162 * Get all GPS location information set in item. Return true if all information can be found. 1163 */ 1164 bool getGPSInfo(double& altitude, double& latitude, double& longitude) const; 1165 1166 /** 1167 * Get GPS location information set in the item, in the GPSCoordinate format 1168 * as described in the XMP specification. Returns a null string in the information cannot be found. 1169 */ 1170 QString getGPSLatitudeString() const; 1171 QString getGPSLongitudeString() const; 1172 1173 /** 1174 * Get GPS location information set in the item, as a double floating point number as in degrees 1175 * where the sign determines the direction ref (North + / South - ; East + / West -). 1176 * Returns true if the information is available. 1177 */ 1178 bool getGPSLatitudeNumber(double* const latitude) const; 1179 bool getGPSLongitudeNumber(double* const longitude) const; 1180 1181 /** 1182 * Get GPS altitude information, in meters, relative to sea level (positive sign above sea level) 1183 */ 1184 bool getGPSAltitude(double* const altitude) const; 1185 1186 /** 1187 * Set all GPS location information into item. Return true if all information have been 1188 * changed in metadata. 1189 */ 1190 bool setGPSInfo(const double altitude, const double latitude, const double longitude); 1191 1192 /** 1193 * Set all GPS location information into item. Return true if all information have been 1194 * changed in metadata. If you do not want altitude to be set, pass a null pointer. 1195 */ 1196 bool setGPSInfo(const double* const altitude, const double latitude, const double longitude); 1197 1198 /** 1199 * Set all GPS location information into item. Return true if all information have been 1200 * changed in metadata. 1201 */ 1202 bool setGPSInfo(const double altitude, const QString& latitude, const QString& longitude); 1203 1204 /** 1205 * Remove all Exif tags relevant of GPS location information. Return true if all tags have been 1206 * removed successfully in metadata. 1207 */ 1208 bool removeGPSInfo(); 1209 1210 /** 1211 * This method converts 'number' to a rational value, returned in the 'numerator' and 1212 * 'denominator' parameters. Set the precision using 'rounding' parameter. 1213 * Use this method if you want to retrieve a most exact rational for a number 1214 * without further properties, without any requirements to the denominator. 1215 */ 1216 static void convertToRational(const double number, 1217 long int* const numerator, 1218 long int* const denominator, 1219 const int rounding); 1220 1221 /** 1222 * This method convert a 'number' to a rational value, returned in 'numerator' and 1223 * 'denominator' parameters. 1224 * This method will be able to retrieve a rational number from a double - if you 1225 * constructed your double with 1.0 / 4786.0, this method will retrieve 1 / 4786. 1226 * If your number is not expected to be rational, use the method above which is just as 1227 * exact with rounding = 4 and more exact with rounding > 4. 1228 */ 1229 static void convertToRationalSmallDenominator(const double number, 1230 long int* const numerator, 1231 long int* const denominator); 1232 1233 /** 1234 * Converts degrees values as a double representation. This code take a care about hemisphere position. 1235 */ 1236 static double convertDegreeAngleToDouble(double degrees, double minutes, double seconds); 1237 1238 1239 /** 1240 * Converts a GPS position stored as rationals in Exif to the form described 1241 * as GPSCoordinate in the XMP specification, either in the from "256,45,34N" or "256,45.566667N" 1242 */ 1243 static QString convertToGPSCoordinateString(const long int numeratorDegrees, 1244 const long int denominatorDegrees, 1245 const long int numeratorMinutes, 1246 const long int denominatorMinutes, 1247 const long int numeratorSeconds, 1248 const long int denominatorSeconds, 1249 const char directionReference); 1250 1251 /** 1252 * Converts a GPS position stored as double floating point number in degrees to the form described 1253 * as GPSCoordinate in the XMP specification. 1254 */ 1255 static QString convertToGPSCoordinateString(const bool isLatitude, 1256 double coordinate); 1257 1258 /** 1259 * Converts a GPSCoordinate string as defined by XMP to three rationals and the direction reference. 1260 * Returns true if the conversion was successful. 1261 * If minutes is given in the fractional form, a denominator of 1000000 for the minutes will be used. 1262 */ 1263 static bool convertFromGPSCoordinateString(const QString& coordinate, 1264 long int* const numeratorDegrees, 1265 long int* const denominatorDegrees, 1266 long int* const numeratorMinutes, 1267 long int* const denominatorMinutes, 1268 long int* const numeratorSeconds, 1269 long int* const denominatorSeconds, 1270 char* const directionReference); 1271 1272 /** 1273 * Convert a GPSCoordinate string as defined by XMP to a double floating point number in degrees 1274 * where the sign determines the direction ref (North + / South - ; East + / West -). 1275 * Returns true if the conversion was successful. 1276 */ 1277 static bool convertFromGPSCoordinateString(const QString& gpsString, 1278 double* const coordinate); 1279 1280 /** 1281 * Converts a GPSCoordinate string to user presentable numbers, integer degrees and minutes and 1282 * double floating point seconds, and a direction reference ('N' or 'S', 'E' or 'W') 1283 */ 1284 static bool convertToUserPresentableNumbers(const QString& coordinate, 1285 int* const degrees, 1286 int* const minutes, 1287 double* const seconds, 1288 char* const directionReference); 1289 1290 /** 1291 * Converts a double floating point number to user presentable numbers, integer degrees and minutes and 1292 * double floating point seconds, and a direction reference ('N' or 'S', 'E' or 'W'). 1293 * The method needs to know for the direction reference 1294 * if the latitude or the longitude is meant by the double parameter. 1295 */ 1296 static void convertToUserPresentableNumbers(const bool isLatitude, 1297 double coordinate, 1298 int* const degrees, 1299 int* const minutes, 1300 double* const seconds, 1301 char* const directionReference); 1302 1303 //@} 1304 1305 protected: 1306 1307 /** 1308 * Set the Program Name and Program Version 1309 * information in Exif and Iptc metadata 1310 */ 1311 bool setProgramId() const; 1312 1313 private: 1314 1315 // Disable copy constructor and operator to prevent potential slicing with this class, reported by Clazy static analyzer. 1316 // https://github.com/KDE/clazy/blob/master/docs/checks/README-copyable-polymorphic.md 1317 // This methods was implemented to be able to pass this class or a derived version to signals and slots. This is very 1318 // Dangerous as virtual methods are present in this polymorphic class and is copyable. 1319 // Instead to use this class in signals and slots, use MetaEngineData container. 1320 // TODO: remove legacy implementations for these methods later if no side effect. 1321 MetaEngine(const MetaEngine& metadata); 1322 MetaEngine& operator=(const MetaEngine& metadata); 1323 1324 private: 1325 1326 /** 1327 * Internal container to store private members. Used to improve binary compatibility 1328 */ 1329 class Private; 1330 Private* const d; 1331 1332 friend class MetaEnginePreviews; 1333 }; 1334 1335 } // namespace Digikam 1336 1337 #endif // DIGIKAM_META_ENGINE_H 1338