1 /* SPDX-FileCopyrightText: 2003-2020 The KPhotoAlbum Development Team
2 
3    SPDX-License-Identifier: GPL-2.0-or-later
4 */
5 
6 #ifndef IMAGEINFO_H
7 #define IMAGEINFO_H
8 
9 #include <kpabase/config-kpa-marble.h>
10 
11 #include "CategoryPtr.h"
12 #include "ExifMode.h"
13 #include "ImageDate.h"
14 #include "MD5.h"
15 
16 #ifdef HAVE_MARBLE
17 #include <Map/GeoCoordinates.h>
18 #endif
19 #include <kpabase/FileName.h>
20 #include <kpabase/StringSet.h>
21 
22 #include <QHash>
23 #include <QRect>
24 #include <QSize>
25 #include <QString>
26 #include <QStringList>
27 
28 namespace Plugins
29 {
30 class ImageInfo;
31 }
32 
33 namespace XMLDB
34 {
35 class Database;
36 }
37 
38 namespace DB
39 {
40 enum RotationMode {
41     RotateImageInfoAndAreas,
42     RotateImageInfoOnly
43 };
44 
45 using Utilities::StringSet;
46 class MemberMap;
47 
48 /**
49  * @brief The FileInformation enum controls the behaviour of the ImageInfo constructor.
50  * Depending on the value, metadata is read from the image file and optionally the Exif database is updated.
51  */
52 enum class FileInformation {
53     Ignore, ///< Do not read additional information from the image file.
54     Read, ///< Read metadata from the image file, but do not update metadata in the Exif database.
55     ReadAndUpdateExifDB ///< Read metadata from the image file and update the Exif database.
56 };
57 
58 enum MediaType { Image = 0x01,
59                  Video = 0x02 };
60 const MediaType anyMediaType = MediaType(Image | Video);
61 typedef unsigned int StackID;
62 
63 typedef QHash<QString, QRect> PositionTags;
64 typedef QHashIterator<QString, QRect> PositionTagsIterator;
65 typedef QHash<QString, PositionTags> TaggedAreas;
66 typedef QHashIterator<QString, PositionTags> TaggedAreasIterator;
67 typedef QHash<QString, StringSet> CategoryInformation;
68 
69 class ImageInfo : public QSharedData
70 {
71 
72 public:
73     /**
74      * @brief ImageInfo constructs an empty ImageInfo.
75      * An empty imageInfo can be detected by calling \c isNull().
76      */
77     ImageInfo();
78     /**
79      * @brief ImageInfo constructor to create an ImageInfo for a file.
80      * This constructor is typically called by the new image finder.
81      * @param fileName
82      * @param type
83      * @param infoMode
84      */
85     explicit ImageInfo(const DB::FileName &fileName, MediaType type = Image, FileInformation infoMode = FileInformation::ReadAndUpdateExifDB);
86     /**
87      * @brief ImageInfo constructor including all fields.
88      * This constructor is typically called when reading ImageInfos from the database file, or when doing an import.
89      * @param fileName
90      * @param label
91      * @param description
92      * @param date
93      * @param angle
94      * @param md5sum
95      * @param size
96      * @param type
97      * @param rating
98      * @param stackId
99      * @param stackOrder
100      */
101     ImageInfo(const DB::FileName &fileName,
102               const QString &label,
103               const QString &description,
104               const ImageDate &date,
105               int angle,
106               const MD5 &md5sum,
107               const QSize &size,
108               MediaType type,
109               short rating = -1,
110               StackID stackId = 0,
111               unsigned int stackOrder = 0);
112     ImageInfo(const ImageInfo &other);
113 
114     FileName fileName() const;
115     void setFileName(const DB::FileName &relativeFileName);
116 
117     void setLabel(const QString &);
118     QString label() const;
119 
120     void setDescription(const QString &);
121     QString description() const;
122 
123     void setDate(const ImageDate &);
124     ImageDate date() const;
125     ImageDate &date();
126     void readExif(const DB::FileName &fullPath, DB::ExifMode mode);
127 
128     void rotate(int degrees, RotationMode mode = RotateImageInfoAndAreas);
129     int angle() const;
130     void setAngle(int angle);
131 
132     short rating() const;
133     void setRating(short rating);
134 
isStacked()135     bool isStacked() const { return m_stackId != 0; }
136     StackID stackId() const;
137 
138     unsigned int stackOrder() const;
139     void setStackOrder(const unsigned int stackOrder);
140 
141     void setVideoLength(int seconds);
142     int videoLength() const;
143 
144     void setCategoryInfo(const QString &key, const StringSet &value);
145     void addCategoryInfo(const QString &category, const StringSet &values);
146     /**
147      * Enable a tag within a category for this image.
148      * Optionally, the tag's position can be given (for positionable categories).
149      * @param category the category name
150      * @param value the tag name
151      * @param area the image region that the tag applies to.
152      */
153     void addCategoryInfo(const QString &category, const QString &value, const QRect &area = QRect());
154     void clearAllCategoryInfo();
155     void removeCategoryInfo(const QString &category, const StringSet &values);
156     void removeCategoryInfo(const QString &category, const QString &value);
157     /**
158      * Set the tagged areas for the image.
159      * It is assumed that the positioned tags have already been set to the ImageInfo
160      * using one of the functions <code>setCategoryInfo</code> or <code>addCategoryInfo</code>.
161      *
162      * @param category the category name.
163      * @param positionedTags a mapping of tag names to image areas.
164      */
165     void setPositionedTags(const QString &category, const PositionTags &positionedTags);
166 
167     bool hasCategoryInfo(const QString &key, const QString &value) const;
168     bool hasCategoryInfo(const QString &key, const StringSet &values) const;
169 
170     QStringList availableCategories() const;
171     StringSet itemsOfCategory(const QString &category) const;
172     void renameItem(const QString &key, const QString &oldValue, const QString &newValue);
173     void renameCategory(const QString &oldName, const QString &newName);
174 
175     bool operator!=(const ImageInfo &other) const;
176     bool operator==(const ImageInfo &other) const;
177     ImageInfo &operator=(const ImageInfo &other);
178 
179     static bool imageOnDisk(const DB::FileName &fileName);
180 
MD5Sum()181     const MD5 &MD5Sum() const { return m_md5sum; }
182     void setMD5Sum(const MD5 &sum, bool storeEXIF = true);
183 
184     void setLocked(bool);
185     bool isLocked() const;
186 
isNull()187     bool isNull() const { return m_null; }
188     QSize size() const;
189     void setSize(const QSize &size);
190 
191     MediaType mediaType() const;
setMediaType(MediaType type)192     void setMediaType(MediaType type)
193     {
194         if (type != m_type)
195             m_dirty = true;
196         m_type = type;
197     }
198     bool isVideo() const;
199 
200     void createFolderCategoryItem(DB::CategoryPtr, DB::MemberMap &memberMap);
201 
202     void copyExtraData(const ImageInfo &from, bool copyAngle = true);
203     void removeExtraData();
204     /**
205      * Merge another ImageInfo into this one.
206      * The other ImageInfo is not altered in any way or removed.
207      */
208     void merge(const ImageInfo &other);
209 
210     TaggedAreas taggedAreas() const;
211     /**
212      * Return the area associated with a tag.
213      * @param category the category name
214      * @param tag the tag name
215      * @return the associated area, or <code>QRect()</code> if no association exists.
216      */
217     QRect areaForTag(QString category, QString tag) const;
218     void setIsMatched(bool isMatched);
219     bool isMatched() const;
220     void setMatchGeneration(int matchGeneration);
221     int matchGeneration() const;
222 #ifdef HAVE_MARBLE
223     Map::GeoCoordinates coordinates() const;
224 #endif
225 
226 protected:
setIsNull(bool b)227     void setIsNull(bool b) { m_null = b; }
isDirty()228     bool isDirty() const { return m_dirty; }
229     void markDirty();
230     bool updateDateInformation(int mode) const;
231 
232     void setStackId(const StackID stackId);
233     friend class XMLDB::Database;
234 
235 private:
236     DB::FileName m_fileName;
237     QString m_label;
238     QString m_description;
239     ImageDate m_date;
240     CategoryInformation m_categoryInfomation;
241     TaggedAreas m_taggedAreas;
242     int m_angle;
243     enum OnDisk { YesOnDisk,
244                   NoNotOnDisk,
245                   Unchecked };
246     mutable OnDisk m_imageOnDisk;
247     MD5 m_md5sum;
248     bool m_null;
249     QSize m_size;
250     MediaType m_type;
251     short m_rating;
252     StackID m_stackId;
253     unsigned int m_stackOrder;
254     int m_videoLength;
255     bool m_isMatched;
256     int m_matchGeneration;
257 #ifdef HAVE_MARBLE
258     mutable Map::GeoCoordinates m_coordinates;
259     mutable bool m_coordsIsSet = false;
260 #endif
261 
262     // Cache information
263     bool m_locked;
264 
265     // Will be set to true after every change
266     bool m_dirty;
267 };
268 }
269 
270 #endif /* IMAGEINFO_H */
271 
272 // vi:expandtab:tabstop=4 shiftwidth=4:
273