1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2005-06-14
7  * Description : digiKam 8/16 bits image management API
8  *
9  * Copyright (C) 2005      by Renchi Raju <renchi dot raju at gmail dot com>
10  * Copyright (C) 2005-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
11  * Copyright (C) 2006-2013 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
12  *
13  * This program is free software; you can redistribute it
14  * and/or modify it under the terms of the GNU General
15  * Public License as published by the Free Software Foundation;
16  * either version 2, or (at your option)
17  * any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * ============================================================ */
25 
26 #ifndef DIGIKAM_DIMG_H
27 #define DIGIKAM_DIMG_H
28 
29 // Qt includes
30 
31 #include <QExplicitlySharedDataPointer>
32 #include <QByteArray>
33 #include <QFileInfo>
34 #include <QFlags>
35 #include <QSize>
36 #include <QRect>
37 #include <QVariant>
38 
39 // Local includes
40 
41 #include "digikam_export.h"
42 #include "drawdecoding.h"
43 #include "dcolor.h"
44 #include "dcolorcomposer.h"
45 #include "historyimageid.h"
46 #include "iccprofile.h"
47 #include "metaengine_data.h"
48 
49 class QImage;
50 class QPixmap;
51 
52 namespace Digikam
53 {
54 
55 class ExposureSettingsContainer;
56 class DImageHistory;
57 class FilterAction;
58 class IccTransform;
59 class DImgLoaderObserver;
60 
61 class DIGIKAM_EXPORT DImg
62 {
63 public:
64 
65     enum FORMAT
66     {
67         /**
68          * NOTE: Order is important here:
69          * See filesaveoptionbox.cpp which use these values to fill a stack of widgets.
70          */
71         NONE = 0,
72         JPEG,
73         PNG,
74         TIFF,
75         JP2K,
76         PGF,
77         HEIF,
78         // Others file formats.
79         RAW,
80         QIMAGE  ///< QImage or ImageMagick
81     };
82 
83     enum ANGLE
84     {
85         ROT90 = 0,
86         ROT180,
87         ROT270,
88         ROTNONE
89     };
90 
91     enum FLIP
92     {
93         HORIZONTAL = 0,
94         VERTICAL
95     };
96 
97     enum COLORMODEL
98     {
99         COLORMODELUNKNOWN = 0,
100         RGB,
101         GRAYSCALE,
102         MONOCHROME,
103         INDEXED,
104         YCBCR,
105         CMYK,
106         CIELAB,
107         COLORMODELRAW
108     };
109 
110 public:
111 
112     /**
113      * Identify file format
114      */
115     static FORMAT fileFormat(const QString& filePath);
116 
117     static QString formatToMimeType(FORMAT frm);
118 
119 public:
120 
121     class Private;
122 
123 public:
124 
125     /**
126      * Create null image
127      */
128     DImg();
129 
130     /**
131      * Load image using QByteArray as file path
132      */
133     explicit DImg(const QByteArray& filePath, DImgLoaderObserver* const observer = nullptr,
134                   const DRawDecoding& rawDecodingSettings = DRawDecoding());
135 
136     /**
137      * Load image using QString as file path
138      */
139     explicit DImg(const QString& filePath, DImgLoaderObserver* const observer = nullptr,
140                   const DRawDecoding& rawDecodingSettings = DRawDecoding());
141 
142     /**
143      * Copy image: Creates a shallow copy that refers to the same shared data.
144      * The two images will be equal. Call detach() or copy() to create deep copies.
145      */
146     DImg(const DImg& image);
147 
148     /**
149      * Copy image: Creates a copy of a QImage object. If the QImage is null, a
150      * null DImg will be created.
151      */
152     explicit DImg(const QImage& image);
153 
154     /**
155      * Create image from data.
156      * If data is 0, a new buffer will be allocated, otherwise the given data will be used:
157      * If copydata is true, the data will be copied to a newly allocated buffer.
158      * If copyData is false, this DImg object will take ownership of the data pointer.
159      * If there is an alpha channel, the data shall be in non-premultiplied form (unassociated alpha).
160      */
161     DImg(uint width, uint height, bool sixteenBit, bool alpha = false, uchar* const data = nullptr, bool copyData = true);
162 
163     ~DImg();
164 
165     /**
166      * Equivalent to the copy constructor
167      */
168     DImg&      operator=(const DImg& image);
169 
170     /** Detaches from shared data and makes sure that this image
171      * is the only one referring to the data.
172      * If multiple images share common data, this image makes a copy
173      * of the data and detaches itself from the sharing mechanism.
174      * Nothing is done if there is just a single reference.
175      */
176     void       detach();
177 
178     /** Returns whether two images are equal.
179      * Two images are equal if and only if they refer to the same shared data.
180      * (Thus, DImg() == DImg() is not true, both instances refer two their
181      * own shared data. image == DImg(image) is true.)
182      * If two or more images refer to the same data, they have the same
183      * image data, bits() returns the same data, they have the same metadata,
184      * and a change to one image also affects the others.
185      * Call detach() to split one image from the group of equal images.
186      */
187     bool        operator==(const DImg& image) const;
188 
189     /**
190      * Replaces image data of this object. Metadata is unchanged. Parameters like constructor above.
191      */
192     void        putImageData(uint width, uint height, bool sixteenBit, bool alpha, uchar* const data, bool copyData = true);
193 
194     /**
195      * Overloaded function, provided for convenience, behaves essentially
196      * like the function above if data is not 0.
197      * Uses current width, height, sixteenBit, and alpha values.
198      * If data is 0, the current data is deleted and the image is set to null
199      * (But metadata unchanged).
200      */
201     void        putImageData(uchar* const data, bool copyData = true);
202 
203     /**
204      * Reset metadata and image data to null image
205      */
206     void        reset();
207 
208     /**
209      * Reset metadata, but do not change image data
210      */
211     void        resetMetaData();
212 
213     /**
214      * Returns the data of this image.
215      * Ownership of the buffer is passed to the caller, this image will be null afterwards.
216      */
217     uchar*      stripImageData();
218 
219     bool        load(const QString& filePath, DImgLoaderObserver* const observer = nullptr,
220                      const DRawDecoding& rawDecodingSettings = DRawDecoding());
221 
222     bool        load(const QString& filePath,
223                      bool loadMetadata, bool loadICCData, bool loadUniqueHash, bool loadHistory,
224                      DImgLoaderObserver* const observer = nullptr,
225                      const DRawDecoding& rawDecodingSettings = DRawDecoding());
226 
227     bool        load(const QString& filePath, int loadFlags, DImgLoaderObserver* const observer,
228                      const DRawDecoding& rawDecodingSettings = DRawDecoding());
229 
230     bool        save(const QString& filePath, FORMAT frm, DImgLoaderObserver* const observer = nullptr);
231     bool        save(const QString& filePath, const QString& format, DImgLoaderObserver* const observer = nullptr);
232 
233     /**
234      * It is common that images are not directly saved to the destination path.
235      * For this reason, save() does not call addAsReferredImage(), and the stored
236      * save path may be wrong.
237      * Call this method after save() with the final destination path.
238      * This path will be stored in the image history as well.
239      */
240     void        imageSavedAs(const QString& savePath);
241 
242     /**
243      * Loads most parts of the meta information, but never the image data.
244      * If loadMetadata is true, the metadata will be available with getComments, getExif, getIptc, getXmp .
245      * If loadICCData is true, the ICC profile will be available with getICCProfile.
246      */
247     bool        loadItemInfo(const QString& filePath, bool loadMetadata = true,
248                              bool loadICCData = true, bool loadUniqueHash = true,
249                              bool loadImageHistory = true);
250 
251     bool        isNull()         const;
252     uint        width()          const;
253     uint        height()         const;
254     QSize       size()           const;
255     uchar*      copyBits()       const;
256     uchar*      bits()           const;
257     uchar*      scanLine(uint i) const;
258     bool        hasAlpha()       const;
259     bool        sixteenBit()     const;
260     quint64     numBytes()       const;
261     quint64     numPixels()      const;
262 
263     /**
264      * Return the number of bytes depth of one pixel : 4 (non sixteenBit) or 8 (sixteen)
265      */
266     int         bytesDepth() const;
267 
268     /**
269      * Return the number of bits depth of one color component for one pixel : 8 (non sixteenBit) or 16 (sixteen)
270      */
271     int         bitsDepth()  const;
272 
273     /**
274      * Returns the file path from which this DImg was originally loaded.
275      * Returns a null string if the DImg was not loaded from a file.
276      */
277     QString     originalFilePath() const;
278 
279     /**
280      * Returns the file path to which this DImg was saved.
281      * Returns the file path set with imageSavedAs(), if that was not called,
282      * save(), if that was not called, a null string.
283      */
284     QString     lastSavedFilePath() const;
285 
286     /**
287      * Returns the color model in which the image was stored in the file.
288      * The color space of the loaded image data is always RGB.
289      */
290     COLORMODEL  originalColorModel() const;
291 
292     /**
293      * Returns the bit depth (in bits per channel, e.g. 8 or 16) of the original file.
294      */
295     int         originalBitDepth() const;
296 
297     /**
298      * Returns the size of the original file.
299      */
300     QSize       originalSize() const;
301 
302     /**
303      * Returns the size of the original file
304      * in the same aspect ratio as size().
305      */
306     QSize       originalRatioSize() const;
307 
308     /**
309      * Returns the file format in form of the FORMAT enum that was detected in the load()
310      * method. Other than the format attribute which is written by the DImgLoader,
311      * this can include the QIMAGE or NONE values.
312      * Returns NONE for images that have not been loaded.
313      * For unknown image formats, a value of QIMAGE can be returned to indicate that the
314      * QImage-based loader will have been used. To find out if this has worked, check
315      * the return value you got from load().
316      */
317     FORMAT      detectedFormat() const;
318 
319     /**
320      * Returns the format string as written by the image loader this image was originally
321      * loaded from. Format strings used include JPEG, PNG, TIFF, PGF, JP2K, RAW, PPM.
322      * For images loaded with the platform QImage loader, the file suffix is used.
323      * Returns null if this DImg was not loaded from a file, but created in memory.
324      */
325     QString     format() const;
326 
327     /**
328      * Returns the format string of the format that this image was last saved to.
329      * An image can be loaded from a file - retrieve that format with fileFormat()
330      * and loadedFormat() - and can the multiple times be saved to different formats.
331      * Format strings used include JPG, PGF, PNG, TIFF and JP2K.
332      * If this file was not save, a null string is returned.
333      */
334     QString     savedFormat() const;
335 
336     /**
337      * Returns the DRawDecoding options that this DImg was loaded with.
338      * If this is not a RAW image or no options were specified, returns DRawDecoding().
339      */
340     DRawDecoding rawDecodingSettings() const;
341 
342     /**
343      * Access a single pixel of the image.
344      * These functions add some safety checks and then use the methods from DColor.
345      * In optimized code working directly on the data,
346      * better use the inline methods from DColor.
347      */
348     DColor      getPixelColor(uint x, uint y) const;
349     void        setPixelColor(uint x, uint y, const DColor& color);
350     void        prepareSubPixelAccess();
351     DColor      getSubPixelColor(float x, float y) const;
352     DColor      getSubPixelColorFast(float x, float y) const;
353 
354     /**
355      * If the image has an alpha channel, check if there exist pixels
356      * which actually have non-opaque color, that is alpha < 1.0.
357      * Note that all pixels are scanned to reach a return value of "false".
358      * If hasAlpha() is false, always returns false.
359      */
360     bool        hasTransparentPixels() const;
361 
362     /**
363      * Return true if the original image file format cannot be saved.
364      * This is depending of DImgLoader::save() implementation. For example
365      * RAW file formats are supported by DImg using dcraw than cannot support
366      * writing operations.
367      */
368     bool       isReadOnly()        const;
369 
370     /**
371      * Metadata manipulation methods
372      */
373     MetaEngineData getMetadata()   const;
374     IccProfile getIccProfile()     const;
375     void       setMetadata(const MetaEngineData& data);
376     void       setIccProfile(const IccProfile& profile);
377 
378     void       setAttribute(const QString& key, const QVariant& value);
379     QVariant   attribute(const QString& key)    const;
380     bool       hasAttribute(const QString& key) const;
381     void       removeAttribute(const QString& key);
382 
383     void       setEmbeddedText(const QString& key, const QString& text);
384     QString    embeddedText(const QString& key) const;
385 
386     const DImageHistory& getItemHistory() const;
387     DImageHistory&       getItemHistory();
388     void                 setItemHistory(const DImageHistory& history);
389     bool                 hasImageHistory() const;
390     DImageHistory        getOriginalImageHistory() const;
391     void                 addFilterAction(const FilterAction& action);
392 
393     /**
394      * Sets a step in the history to constitute the beginning of a branch.
395      * Use setHistoryBranch() to take getOriginalImageHistory() and set the first added step as a branch.
396      * Use setHistoryBranchForLastSteps(n) to start the branch before the last n steps in the history.
397      * (Assume the history had 3 steps and you added 2, call setHistoryBranchForLastSteps(2))
398      * Use setHistoryBranchAfter() if have a copy of the history before branching,
399      * the first added step on top of that history will be made a branch.
400      */
401     void                 setHistoryBranchAfter(const DImageHistory& historyBeforeBranch, bool isBranch = true);
402     void                 setHistoryBranchForLastSteps(int numberOfLastHistorySteps, bool isBranch = true);
403     void                 setHistoryBranch(bool isBranch = true);
404 
405     /**
406      * When saving, several changes to the image metadata are necessary
407      * before it can safely be written to the new file.
408      * This method updates the stored meta engine object in preparation to a subsequent
409      * call to save() with the same target file.
410      * 'intendedDestPath' is the finally intended file name. Do not give the temporary
411      *   file name if you are going to save() to a temp file.
412      * 'destMimeType' is destination type mime. In some cases, metadata is updated depending on this value.
413      * 'originalFileName' is the original file's name, for simplistic history tracking in metadata.
414      *   This is completely independent from the DImageHistory framework.
415      * For the 'flags' see below.
416      * Not all steps are optional and can be controlled with flags.
417      */
418     enum PrepareMetadataFlag
419     {
420         /**
421          * A small preview can be stored in the metadata.
422          * Remove old preview entries
423          */
424         RemoveOldMetadataPreviews = 1 << 0,
425         /**
426          * Create a new preview from current image data.
427          */
428         CreateNewMetadataPreview  = 1 << 1,
429         /**
430          * Set the exif orientation tag to "normal"
431          * Applicable if the image data was rotated according to the tag
432          */
433         ResetExifOrientationTag   = 1 << 2,
434         /**
435          * Creates a new UUID for the image history.
436          * Applicable if the file was changed.
437          */
438         CreateNewImageHistoryUUID = 1 << 3,
439 
440         PrepareMetadataFlagsAll   = RemoveOldMetadataPreviews |
441                                     CreateNewMetadataPreview  |
442                                     ResetExifOrientationTag   |
443                                     CreateNewImageHistoryUUID
444     };
445     Q_DECLARE_FLAGS(PrepareMetadataFlags, PrepareMetadataFlag)
446 
447     void prepareMetadataToSave(const QString& intendedDestPath,
448                                const QString& destMimeType,
449                                const QString& originalFileName = QString(),
450                                PrepareMetadataFlags flags      = PrepareMetadataFlagsAll);
451 
452     /**
453      * For convenience: Including all flags, except for ResetExifOrientationTag which can be selected.
454      * Uses originalFilePath() to fill the original file name.
455      */
456     void prepareMetadataToSave(const QString& intendedDestPath,
457                                const QString& destMimeType,
458                                bool           resetExifOrientationTag);
459 
460     /**
461      * Create a HistoryImageId for _this_ image _already_ saved at the given file path.
462      */
463     HistoryImageId createHistoryImageId(const QString& filePath, HistoryImageId::Type type);
464 
465     /**
466      * If you have saved this DImg to filePath, and want to continue using this DImg object
467      * to add further changes to the image history, you can call this method to add to the image history
468      * a reference to the just saved image.
469      * First call updateMetadata(), then call save(), then call addAsReferredImage().
470      * Do not call this directly after loading, before applying any changes:
471      * The history is correctly initialized when loading.
472      * If you need to insert the referred file to an entry which is not the last entry,
473      * which may happen if the added image was saved after this image's history was created,
474      * you can use insertAsReferredImage.
475      * The added id is returned.
476      */
477     HistoryImageId addAsReferredImage(const QString& filePath, HistoryImageId::Type type = HistoryImageId::Intermediate);
478     void           addAsReferredImage(const HistoryImageId& id);
479     void           insertAsReferredImage(int afterHistoryStep, const HistoryImageId& otherImagesId);
480 
481     /**
482      * In the history, adjusts the UUID of the ImageHistoryId of the current file.
483      * Call this if you have associated a UUID with this file which is not written to the metadata.
484      * If there is already a UUID present, read from metadata, it will not be replaced.
485      */
486     void addCurrentUniqueImageId(const QString& uuid);
487 
488     /**
489      * Retrieves the Exif orientation, either from the LoadSaveThread info provider if available,
490      * or from the metadata
491      */
492     int exifOrientation(const QString& filePath);
493 
494     /**
495      * When loaded from a file, some attributes like format and isReadOnly still depend on this
496      * originating file. When saving in a different format to a different file,
497      * you may wish to switch these attributes to the new file.
498      * - fileOriginData() returns the current origin data, bundled in the returned QVariant.
499      * - setFileOriginData() takes such a variant and adjusts the properties
500      * - lastSavedFileOriginData() returns the origin data as if the image was loaded from
501      *   the last saved image.
502      * - switchOriginToLastSaved is equivalent to setting origin data returned from lastSavedFileOriginData()
503      *
504      * Example: an image loaded from a RAW and saved to PNG will be read-only and format RAW.
505      * After calling switchOriginToLastSaved, it will not be read-only, format will be PNG,
506      * and rawDecodingSettings will be null. detectedFormat() will not change.
507      * In the history, the last referred image that was added (as intermediate) is made
508      * the new Current image.
509      * NOTE: Set the saved image path with imageSavedAs() before!
510      */
511     QVariant    fileOriginData()          const;
512     void        setFileOriginData(const QVariant& data);
513     QVariant    lastSavedFileOriginData() const;
514     void        switchOriginToLastSaved();
515 
516     /**
517      * Return a deep copy of full image
518      */
519     DImg       copy() const;
520 
521     /**
522      * Return a deep copy of the image, but do not include metadata.
523      */
524     DImg       copyImageData() const;
525 
526     /**
527      * Return an image that contains a deep copy of
528      * this image's metadata and the information associated
529      * with the image data (width, height, hasAlpha, sixteenBit),
530      * but no image data, i.e. isNull() is true.
531      */
532     DImg       copyMetaData() const;
533 
534     /**
535      * Return a region of image
536      */
537     DImg       copy(const QRect& rect)          const;
538     DImg       copy(const QRectF& relativeRect) const;
539     DImg       copy(int x, int y, int w, int h) const;
540 
541     /**
542      * Copy a region of pixels from a source image to this image.
543      * Parameters:
544      * sx|sy  Coordinates in the source image of the rectangle to be copied
545      * w h    Width and height of the rectangle (Default, or when both are -1: whole source image)
546      * dx|dy  Coordinates in this image of the rectangle in which the region will be copied
547      * (Default: 0|0)
548      * The bit depth of source and destination must be identical.
549      */
550     void       bitBltImage(const DImg* const src, int dx, int dy);
551     void       bitBltImage(const DImg* const src, int sx, int sy, int dx, int dy);
552     void       bitBltImage(const DImg* const src, int sx, int sy, int w, int h, int dx, int dy);
553     void       bitBltImage(const uchar* const src, int sx, int sy, int w, int h, int dx, int dy,
554                            uint swidth, uint sheight, int sdepth);
555 
556     /**
557      * Blend src image on this image (this is dest) with the specified composer
558      * and multiplication flags. See documentation of DColorComposer for more info.
559      * For the other arguments, see documentation of bitBltImage above.
560      */
561     void       bitBlendImage(DColorComposer* const composer, const DImg* const src,
562                              int sx, int sy, int w, int h, int dx, int dy,
563                              DColorComposer::MultiplicationFlags multiplicationFlags =
564                                  DColorComposer::NoMultiplication);
565 
566     /**
567      * For the specified region, blend this image on the given color with the specified
568      * composer and multiplication flags. See documentation of DColorComposer for more info.
569      * Note that the result pixel is again written to this image, which is, for the blending, source.
570      */
571     void       bitBlendImageOnColor(DColorComposer* const composer, const DColor& color,
572                                     int x, int y, int w, int h,
573                                     DColorComposer::MultiplicationFlags multiplicationFlags =
574                                     DColorComposer::NoMultiplication);
575     void       bitBlendImageOnColor(const DColor& color, int x, int y, int w, int h);
576     void       bitBlendImageOnColor(const DColor& color);
577 
578     /**
579      * QImage wrapper methods
580      */
581     QImage     copyQImage()                           const;
582     QImage     copyQImage(const QRect& rect)          const;
583     QImage     copyQImage(const QRectF& relativeRect) const;
584     QImage     copyQImage(int x, int y, int w, int h) const;
585 
586     /**
587      * Crop image to the specified region
588      */
589     void       crop(const QRect& rect);
590     void       crop(int x, int y, int w, int h);
591 
592     /**
593      * Set width and height of this image, smoothScale it to the given size
594      */
595     void       resize(int w, int h);
596 
597     /**
598      * If the image has an alpha channel and transparent pixels,
599      * it will be blended on the specified color and the alpha channel will be removed.
600      * This is a no-op if hasTransparentPixels() is false, but this method can be expensive,
601      * therefore it is _not_ checked inside removeAlphaChannel().
602      * (the trivial hasAlpha() is checked)
603      */
604     void       removeAlphaChannel(const DColor& destColor);
605     void       removeAlphaChannel();
606 
607     /**
608      * Return a version of this image scaled to the specified size with the specified mode.
609      * See QSize documentation for information on available modes
610      */
611     DImg       smoothScale(int width, int height, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio) const;
612     DImg       smoothScale(const QSize& destSize, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio) const;
613 
614     /**
615      * Executes the same scaling as smoothScale(width, height), but from the result of this call,
616      * returns only the section specified by clipx, clipy, clipwidth, clipheight.
617      * This is thus equivalent to calling
618      * Dimg scaled = smoothScale(width, height); scaled.crop(clipx, clipy, clipwidth, clipheight);
619      * but potentially much faster.
620      * In smoothScaleSection, you specify the source region, here, the result region.
621      * It will often not be possible to find _integer_ source coordinates for a result region!
622      */
623     DImg smoothScaleClipped(int width, int height, int clipx, int clipy, int clipwidth, int clipheight) const;
624     DImg smoothScaleClipped(const QSize& destSize, const QRect& clip) const;
625 
626     /**
627      * Take the region specified by the rectangle sx|sy, width and height sw * sh,
628      * and scale it to an image with size dw * dh
629      */
630     DImg       smoothScaleSection(int sx, int sy, int sw, int sh, int dw, int dh) const;
631     DImg       smoothScaleSection(const QRect& sourceRect, const QSize& destSize) const;
632 
633     void       rotate(ANGLE angle);
634     void       flip(FLIP direction);
635 
636     /**
637      * Rotates and/or flip the DImg according to the given DMetadata::Orientation,
638      * so that the current state is orientation and the resulting step is normal orientation.
639      * Returns true if the image was actually rotated or flipped (e.g. if ORIENTATION_NORMAL
640      * is given, returns false, because no action is taken).
641      */
642     bool       rotateAndFlip(int orientation);
643 
644     /**
645      * Reverses the previous function.
646      */
647     bool       reverseRotateAndFlip(int orientation);
648 
649     /**
650      * Utility to make sure that an image is rotated according to Exif tag.
651      * Detects if an image has previously already been rotated: You can
652      * call this method more than one time on the same image.
653      * Returns true if the image has actually been rotated or flipped.
654      * Returns false if a rotation was not needed.
655      */
656     bool       wasExifRotated();
657     bool       exifRotate(const QString& filePath);
658 
659     /**
660      * Reverses the previous function
661      */
662     bool       reverseExifRotate(const QString& filePath);
663 
664     /**
665      * Returns current DMetadata::Orientation from DImg
666      */
667     int        orientation() const;
668 
669     /** Rotates and/or flip the DImg according to the given transform action,
670      * which is a MetaEngineRotation::TransformAction.
671      * Returns true if the image was actually rotated or flipped.
672      */
673     bool       transform(int transformAction);
674 
675     QPixmap    convertToPixmap()                              const;
676     QPixmap    convertToPixmap(IccTransform& monitorICCtrans) const;
677 
678     /**
679      * Return a mask image where pure white and pure black pixels are over-colored.
680      * This way is used to identify over and under exposed pixels.
681      */
682     QImage     pureColorMask(ExposureSettingsContainer* const expoSettings) const;
683 
684     /**
685      * Convert depth of image. Depth is bytesDepth * bitsDepth.
686      * If depth is 32, converts to 8 bits,
687      * if depth is 64, converts to 16 bits.
688      */
689     void       convertDepth(int depth);
690 
691     /**
692      * Wrapper methods for convertDepth
693      */
694     void       convertToSixteenBit();
695     void       convertToEightBit();
696     void       convertToDepthOfImage(const DImg* const otherImage);
697 
698     /**
699      * Fill whole image with specified color.
700      * The bit depth of the color must be identical to the depth of this image.
701      */
702     void       fill(const DColor& color);
703 
704     /**
705      * This methods return a 128-bit MD5 hex digest which is meant to uniquely identify
706      * the file. The hash is calculated on parts of the file and the file metadata.
707      * It cannot be used to find similar images. It is not calculated from the image data.
708      * The hash will be returned as a 32-byte hexadecimal string.
709      *
710      * If you already have a DImg object of the file, use the member method.
711      * The object does not need to have the full image data loaded, but it shall at least
712      * have been loaded with loadItemInfo with loadMetadata = true, or have the metadata
713      * set later with setComments, setExif, setIptc, setXmp.
714      * If the object does not have the metadata loaded, a non-null, but invalid hash will
715      * be returned! In this case, use the static method.
716      * If the image has been loaded with loadUniqueHash = true, the hash can be retrieved
717      * with the member method.
718      *
719      * You do not need a DImg object of the file to retrieve the unique hash;
720      * Use the static method and pass just the file path.
721      */
722     QByteArray getUniqueHash();
723     static QByteArray getUniqueHash(const QString& filePath);
724 
725     /**
726      * This methods return a 128-bit MD5 hex digest which is meant to uniquely identify
727      * the file. The hash is calculated on parts of the file.
728      * It cannot be used to find similar images. It is not calculated from the image data.
729      * The hash will be returned as a 32-byte hexadecimal string.
730      *
731      * If you already have a DImg object loaded from the file, use the member method.
732      * If the image has been loaded with loadUniqueHash = true, the hash will already
733      * be available.
734      *
735      * You do not need a DImg object of the file to retrieve the unique hash;
736      * Use the static method and pass just the file path.
737      */
738     QByteArray getUniqueHashV2();
739     static QByteArray getUniqueHashV2(const QString& filePath);
740 
741     /**
742      * This method creates a new 256-bit UUID meant to be globally unique.
743      * The UUID will be returned as a 64-byte hexadecimal string.
744      * At least 128bits of the UUID will be created by the platform random number
745      * generator. The rest may be created from a content-based hash similar to the uniqueHash, see above.
746      * This method only generates a new UUID for this image without in any way changing this image object
747      * or saving the UUID anywhere.
748      */
749     QByteArray createImageUniqueId();
750 
751     /**
752      * Helper method to translate enum values to user presentable strings
753      */
754     static QString colorModelToString(COLORMODEL colorModel);
755 
756     /**
757      * Return true if image file is an animation, as GIFa or NMG
758      */
759     static bool isAnimatedImage(const QString& filePath);
760 
761 private:
762 
763     DImg(const DImg& image, uint w, uint h);
764 
765     void copyMetaData(const QExplicitlySharedDataPointer<Private>& src);
766     void copyImageData(const QExplicitlySharedDataPointer<Private>& src);
767     void setImageData(bool null, uint width, uint height, bool sixteenBit, bool alpha);
768     void setImageDimension(uint width, uint height);
769     size_t allocateData() const;
770 
771     bool clipped(int& x, int& y, int& w, int& h, uint width, uint height) const;
772 
773     QDateTime         creationDateFromFilesystem(const QFileInfo& fileInfo) const;
774 
775     static QByteArray createUniqueHash(const QString& filePath, const QByteArray& ba);
776     static QByteArray createUniqueHashV2(const QString& filePath);
777 
778     void bitBlt(const uchar* const src, uchar* const dest,
779                 int sx, int sy, int w, int h, int dx, int dy,
780                 uint swidth, uint sheight, uint dwidth, uint dheight,
781                 bool sixteenBit, int sdepth, int ddepth);
782     void bitBlend(DColorComposer* const composer, uchar* const src, uchar* const dest,
783                   int sx, int sy, int w, int h, int dx, int dy,
784                   uint swidth, uint sheight, uint dwidth, uint dheight,
785                   bool sixteenBit, int sdepth, int ddepth,
786                   DColorComposer::MultiplicationFlags multiplicationFlags);
787     void bitBlendOnColor(DColorComposer* const composer, const DColor& color,
788                          uchar* data, int x, int y, int w, int h,
789                          uint width, uint height, bool sixteenBit, int depth,
790                          DColorComposer::MultiplicationFlags multiplicationFlags);
791     bool normalizeRegionArguments(int& sx, int& sy, int& w, int& h, int& dx, int& dy,
792                                   uint swidth, uint sheight, uint dwidth, uint dheight) const;
793 
794 private:
795 
796     QExplicitlySharedDataPointer<Private> m_priv;
797 
798     friend class DImgLoader;
799 };
800 
801 } // namespace Digikam
802 
803 Q_DECLARE_OPERATORS_FOR_FLAGS(Digikam::DImg::PrepareMetadataFlags)
804 
805 #endif // DIGIKAM_DIMG_H
806