Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgslayoutitempicture.h 3 : : ------------------- 4 : : begin : October 2017 5 : : copyright : (C) 2017 by Nyall Dawson 6 : : email : nyall dot dawson at gmail dot com 7 : : ***************************************************************************/ 8 : : 9 : : /*************************************************************************** 10 : : * * 11 : : * This program is free software; you can redistribute it and/or modify * 12 : : * it under the terms of the GNU General Public License as published by * 13 : : * the Free Software Foundation; either version 2 of the License, or * 14 : : * (at your option) any later version. * 15 : : * * 16 : : ***************************************************************************/ 17 : : #ifndef QGSLAYOUTITEMPICTURE_H 18 : : #define QGSLAYOUTITEMPICTURE_H 19 : : 20 : : #include "qgis_core.h" 21 : : #include "qgslayoutitem.h" 22 : : #include <QFile> 23 : : #include <QImage> 24 : : #include <QSvgRenderer> 25 : : 26 : : class QgsLayoutItemMap; 27 : : class QgsExpression; 28 : : class QgsLayoutNorthArrowHandler; 29 : : 30 : : /** 31 : : * \ingroup core 32 : : * \brief A layout item subclass that displays SVG files or raster format images (jpg, png, ...). 33 : : * \since QGIS 3.0 34 : : */ 35 : : class CORE_EXPORT QgsLayoutItemPicture: public QgsLayoutItem 36 : : { 37 : 0 : Q_OBJECT 38 : : public: 39 : : 40 : : /** 41 : : * Controls how pictures are scaled within the item's frame 42 : : */ 43 : : enum ResizeMode 44 : : { 45 : : Zoom, //!< Enlarges image to fit frame while maintaining aspect ratio of picture 46 : : Stretch, //!< Stretches image to fit frame, ignores aspect ratio 47 : : Clip, //!< Draws image at original size and clips any portion which falls outside frame 48 : : ZoomResizeFrame, //!< Enlarges image to fit frame, then resizes frame to fit resultant image 49 : : FrameToImageSize //!< Sets size of frame to match original size of image without scaling 50 : : }; 51 : : 52 : : /** 53 : : * Format of source image 54 : : */ 55 : : enum Format 56 : : { 57 : : FormatSVG, //!< SVG image 58 : : FormatRaster, //!< Raster image 59 : : FormatUnknown, //!< Invalid or unknown image type 60 : : }; 61 : : 62 : : //! Method for syncing rotation to a map's North direction 63 : : enum NorthMode 64 : : { 65 : : GridNorth = 0, //!< Align to grid north 66 : : TrueNorth, //!< Align to true north 67 : : }; 68 : : 69 : : /** 70 : : * Constructor for QgsLayoutItemPicture, with the specified parent \a layout. 71 : : */ 72 : : QgsLayoutItemPicture( QgsLayout *layout ); 73 : : 74 : : int type() const override; 75 : : QIcon icon() const override; 76 : : 77 : : /** 78 : : * Returns a new picture item for the specified \a layout. 79 : : * 80 : : * The caller takes responsibility for deleting the returned object. 81 : : */ 82 : : static QgsLayoutItemPicture *create( QgsLayout *layout ) SIP_FACTORY; 83 : : 84 : : 85 : : /** 86 : : * Sets the source \a path of the image (may be svg or a raster format). Data defined 87 : : * picture source may override this value. The path can either be a local path 88 : : * or a remote (http) path. 89 : : * 90 : : * Ideally, the \a format argument should specify the image format. 91 : : * 92 : : * \see picturePath() 93 : : */ 94 : : void setPicturePath( const QString &path, Format format = FormatUnknown ); 95 : : 96 : : /** 97 : : * Returns the path of the source image. Data defined picture source may override 98 : : * this value. The path can either be a local path or a remote (http) path. 99 : : * \returns path for the source image 100 : : * \see setPicturePath() 101 : : * \see evaluatedPath() 102 : : */ 103 : : QString picturePath() const; 104 : : 105 : : /** 106 : : * Returns the rotation used for drawing the picture within the item's frame, 107 : : * in degrees clockwise. 108 : : * \see setPictureRotation() 109 : : * \see linkedMap() 110 : : */ 111 : : double pictureRotation() const { return mPictureRotation; } 112 : : 113 : : /** 114 : : * Sets the \a map object for rotation. 115 : : * 116 : : * If this is set then the picture will be rotated by the same 117 : : * amount as the specified map object. This is useful especially for 118 : : * syncing north arrows with a map item. 119 : : * 120 : : * \see setPictureRotation() 121 : : * \see linkedMap() 122 : : */ 123 : : void setLinkedMap( QgsLayoutItemMap *map ); 124 : : 125 : : /** 126 : : * Returns the linked rotation map, if set. An NULLPTR means map rotation is 127 : : * disabled. If this is set then the picture is rotated by the same amount 128 : : * as the specified map object. 129 : : * \see setLinkedMap() 130 : : */ 131 : : QgsLayoutItemMap *linkedMap() const; 132 : : 133 : : /** 134 : : * Returns the mode used to align the picture to a map's North. 135 : : * \see setNorthMode() 136 : : * \see northOffset() 137 : : */ 138 : : NorthMode northMode() const; 139 : : 140 : : /** 141 : : * Sets the \a mode used to align the picture to a map's North. 142 : : * \see northMode() 143 : : * \see setNorthOffset() 144 : : */ 145 : : void setNorthMode( NorthMode mode ); 146 : : 147 : : /** 148 : : * Returns the offset added to the picture's rotation from a map's North. 149 : : * \see setNorthOffset() 150 : : * \see northMode() 151 : : */ 152 : : double northOffset() const; 153 : : 154 : : /** 155 : : * Sets the \a offset added to the picture's rotation from a map's North. 156 : : * \see northOffset() 157 : : * \see setNorthMode() 158 : : */ 159 : : void setNorthOffset( double offset ); 160 : : 161 : : /** 162 : : * Returns the resize mode used for drawing the picture within the layout 163 : : * item's frame. 164 : : * \see setResizeMode() 165 : : */ 166 : : ResizeMode resizeMode() const { return mResizeMode; } 167 : : 168 : : /** 169 : : * Sets the picture's \a anchor point, which controls how it is placed 170 : : * within the picture item's frame. 171 : : * \see pictureAnchor() 172 : : */ 173 : : void setPictureAnchor( QgsLayoutItem::ReferencePoint anchor ); 174 : : 175 : : /** 176 : : * Returns the picture's current anchor, which controls how it is placed 177 : : * within the picture item's frame. 178 : : * \see setPictureAnchor() 179 : : */ 180 : : QgsLayoutItem::ReferencePoint pictureAnchor() const { return mPictureAnchor; } 181 : : 182 : : /** 183 : : * Returns the fill color used for parametrized SVG files. 184 : : * \see setSvgFillColor() 185 : : * \see svgStrokeColor() 186 : : */ 187 : : QColor svgFillColor() const { return mSvgFillColor; } 188 : : 189 : : /** 190 : : * Sets the fill \a color used for parametrized SVG files. 191 : : * \note This setting only has an effect on parametrized SVG files, and is ignored for 192 : : * non-parametrized SVG files. 193 : : * \see svgFillColor() 194 : : * \see setSvgStrokeColor() 195 : : */ 196 : : void setSvgFillColor( const QColor &color ); 197 : : 198 : : /** 199 : : * Returns the stroke color used for parametrized SVG files. 200 : : * \see setSvgStrokeColor() 201 : : * \see svgFillColor() 202 : : */ 203 : : QColor svgStrokeColor() const { return mSvgStrokeColor; } 204 : : 205 : : /** 206 : : * Sets the stroke \a color used for parametrized SVG files. 207 : : * \param color stroke color. 208 : : * \note This setting only has an effect on parametrized SVG files, and is ignored for 209 : : * non-parametrized SVG files. 210 : : * \see svgStrokeColor() 211 : : * \see setSvgFillColor() 212 : : */ 213 : : void setSvgStrokeColor( const QColor &color ); 214 : : 215 : : /** 216 : : * Returns the stroke width (in layout units) used for parametrized SVG files. 217 : : * \see setSvgStrokeWidth() 218 : : * \see svgStrokeColor() 219 : : */ 220 : : double svgStrokeWidth() const { return mSvgStrokeWidth; } 221 : : 222 : : /** 223 : : * Sets the stroke \a width (in layout units) used for parametrized SVG files. 224 : : * \note This setting only has an effect on parametrized SVG files, and is ignored for 225 : : * non-parametrized SVG files. 226 : : * \see svgStrokeWidth() 227 : : * \see setSvgStrokeColor() 228 : : */ 229 : : void setSvgStrokeWidth( double width ); 230 : : 231 : : /** 232 : : * Returns the current picture mode (image format). 233 : : * \see setMode() 234 : : */ 235 : : Format mode() const { return mMode; } 236 : : 237 : : /** 238 : : * Sets the current picture \a mode (image format). 239 : : * \see mode() 240 : : * \since QGIS 3.14 241 : : */ 242 : : void setMode( Format mode ); 243 : : 244 : : void finalizeRestoreFromXml() override; 245 : : 246 : : /** 247 : : * Returns TRUE if the source image is missing and the picture 248 : : * cannot be rendered. 249 : : * 250 : : * \since QGIS 3.6 251 : : */ 252 : : bool isMissingImage() const; 253 : : 254 : : /** 255 : : * Returns the current evaluated picture path, which includes 256 : : * the result of data defined path overrides. 257 : : * 258 : : * \see picturePath() 259 : : * \since QGIS 3.6 260 : : */ 261 : : QString evaluatedPath() const; 262 : : 263 : : public slots: 264 : : 265 : : /** 266 : : * Sets the picture \a rotation within the item bounds, in degrees clockwise. This does not affect 267 : : * the item's frame, only the way the picture is drawn within the item. 268 : : * \see pictureRotation() 269 : : */ 270 : : void setPictureRotation( double rotation ); 271 : : 272 : : /** 273 : : * Sets the resize \a mode used for drawing the picture within the item bounds. 274 : : * \param mode ResizeMode to use for image file 275 : : * \see resizeMode 276 : : */ 277 : : void setResizeMode( QgsLayoutItemPicture::ResizeMode mode ); 278 : : 279 : : /** 280 : : * Recalculates the source image (if using an expression for picture's source) 281 : : * and reloads and redraws the picture. 282 : : * \param context expression context for evaluating data defined picture sources 283 : : */ 284 : : void refreshPicture( const QgsExpressionContext *context = nullptr ); 285 : : 286 : : /** 287 : : * Forces a recalculation of the picture's frame size 288 : : */ 289 : : void recalculateSize(); 290 : : 291 : : void refreshDataDefinedProperty( QgsLayoutObject::DataDefinedProperty property = QgsLayoutObject::AllProperties ) override; 292 : : 293 : : signals: 294 : : //! Emitted on picture rotation change 295 : : void pictureRotationChanged( double newRotation ); 296 : : 297 : : protected: 298 : : 299 : : void draw( QgsLayoutItemRenderContext &context ) override; 300 : : QSizeF applyItemSizeConstraint( QSizeF targetSize ) override; 301 : : bool writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const override; 302 : : bool readPropertiesFromElement( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context ) override; 303 : : 304 : : private: 305 : : 306 : : QgsLayoutItemPicture() = delete; 307 : : 308 : : //! Calculates bounding rect for svg file (mSourcefile) such that aspect ratio is correct 309 : : QRectF boundedSVGRect( double deviceWidth, double deviceHeight ); 310 : : //! Calculates bounding rect for image such that aspect ratio is correct 311 : : QRectF boundedImageRect( double deviceWidth, double deviceHeight ); 312 : : 313 : : //! Returns size of current raster or svg picture 314 : : QSizeF pictureSize(); 315 : : 316 : : QImage mImage; 317 : : QSvgRenderer mSVG; 318 : : //! Absolute path to the image (may be also HTTP URL) 319 : : QString mSourcePath; 320 : : Format mMode = FormatUnknown; 321 : : 322 : : QSize mDefaultSvgSize; 323 : : 324 : : //! Image rotation 325 : : double mPictureRotation = 0; 326 : : 327 : : QString mRotationMapUuid; 328 : : 329 : : //! Width of the picture (in mm) 330 : : double mPictureWidth = 0.0; 331 : : //! Height of the picture (in mm) 332 : : double mPictureHeight = 0.0; 333 : : 334 : : ResizeMode mResizeMode = QgsLayoutItemPicture::Zoom; 335 : : QgsLayoutItem::ReferencePoint mPictureAnchor = UpperLeft; 336 : : 337 : : QColor mSvgFillColor = QColor( 255, 255, 255 ); 338 : : QColor mSvgStrokeColor = QColor( 0, 0, 0 ); 339 : : double mSvgStrokeWidth = 0.2; 340 : : 341 : : bool mHasExpressionError = false; 342 : : bool mLoaded = false; 343 : : bool mLoadingSvg = false; 344 : : bool mIsMissingImage = false; 345 : : QString mEvaluatedPath; 346 : : 347 : : QgsLayoutNorthArrowHandler *mNorthArrowHandler = nullptr; 348 : : 349 : : //! Loads an image file into the picture item and redraws the item 350 : : void loadPicture( const QVariant &data ); 351 : : 352 : : /** 353 : : * Returns part of a raster image which will be shown, given current picture 354 : : * anchor settings 355 : : */ 356 : : QRect clippedImageRect( double &boundRectWidthMM, double &boundRectHeightMM, QSize imageRectPixels ); 357 : : 358 : : /** 359 : : * Loads a remote picture for the item 360 : : */ 361 : : void loadRemotePicture( const QString &url ); 362 : : 363 : : /** 364 : : * Loads a local picture for the item 365 : : */ 366 : : void loadLocalPicture( const QString &path ); 367 : : 368 : : void loadPictureUsingCache( const QString &path ); 369 : : 370 : : QgsLayoutItemPicture( const QgsLayoutItemPicture & ) = delete; 371 : : QgsLayoutItemPicture &operator=( const QgsLayoutItemPicture & ) = delete; 372 : : 373 : : private slots: 374 : : 375 : : void updateNorthArrowRotation( double rotation ); 376 : : 377 : : void shapeChanged(); 378 : : 379 : : friend class QgsCompositionConverter; 380 : : friend class TestQgsCompositionConverter; 381 : : 382 : : }; 383 : : 384 : : #endif // QGSLAYOUTITEMPICTURE_H