QGIS API Documentation  2.3.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgscomposerpicture.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscomposerpicture.cpp
3  -------------------
4  begin : September 2005
5  copyright : (C) 2005 by Radim Blazek
6  email : radim.blazek@gmail.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 
18 #include "qgscomposerpicture.h"
19 #include "qgscomposermap.h"
20 #include "qgscomposition.h"
21 #include "qgsproject.h"
22 #include <QDomDocument>
23 #include <QDomElement>
24 #include <QFileInfo>
25 #include <QImageReader>
26 #include <QPainter>
27 #include <QSvgRenderer>
28 
29 
31  : QgsComposerItem( composition ), mMode( Unknown ), mPictureRotation( 0 ), mRotationMap( 0 )
32 {
33  mPictureWidth = rect().width();
34 }
35 
36 QgsComposerPicture::QgsComposerPicture(): QgsComposerItem( 0 ), mMode( Unknown ), mPictureRotation( 0 ), mRotationMap( 0 )
37 {
38  mPictureHeight = rect().height();
39 }
40 
42 {
43 
44 }
45 
46 void QgsComposerPicture::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
47 {
48  Q_UNUSED( itemStyle );
49  Q_UNUSED( pWidget );
50  if ( !painter )
51  {
52  return;
53  }
54 
55  drawBackground( painter );
56 
57  //int newDpi = ( painter->device()->logicalDpiX() + painter->device()->logicalDpiY() ) / 2;
58 
59  if ( mMode != Unknown )
60  {
61  double boundRectWidthMM = mPictureWidth;
62  double boundRectHeightMM = mPictureHeight;
63 
64  painter->save();
65  painter->translate( rect().width() / 2.0, rect().height() / 2.0 );
66  painter->rotate( mPictureRotation );
67  painter->translate( -boundRectWidthMM / 2.0, -boundRectHeightMM / 2.0 );
68 
69  if ( mMode == SVG )
70  {
71  mSVG.render( painter, QRectF( 0, 0, boundRectWidthMM, boundRectHeightMM ) );
72  }
73  else if ( mMode == RASTER )
74  {
75  painter->drawImage( QRectF( 0, 0, boundRectWidthMM, boundRectHeightMM ), mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
76  }
77 
78  painter->restore();
79  }
80 
81  //frame and selection boxes
82  drawFrame( painter );
83  if ( isSelected() )
84  {
85  drawSelectionBoxes( painter );
86  }
87 }
88 
89 void QgsComposerPicture::setPictureFile( const QString& path )
90 {
91  mSourceFile.setFileName( path );
92  if ( !mSourceFile.exists() )
93  {
94  mMode = Unknown;
95  }
96 
97  QFileInfo sourceFileInfo( mSourceFile );
98  QString sourceFileSuffix = sourceFileInfo.suffix();
99  if ( sourceFileSuffix.compare( "svg", Qt::CaseInsensitive ) == 0 )
100  {
101  //try to open svg
102  mSVG.load( mSourceFile.fileName() );
103  if ( mSVG.isValid() )
104  {
105  mMode = SVG;
106  QRect viewBox = mSVG.viewBox(); //take width/height ratio from view box instead of default size
107  mDefaultSvgSize.setWidth( viewBox.width() );
108  mDefaultSvgSize.setHeight( viewBox.height() );
109  }
110  else
111  {
112  mMode = Unknown;
113  }
114  }
115  else
116  {
117  //try to open raster with QImageReader
118  QImageReader imageReader( mSourceFile.fileName() );
119  if ( imageReader.read( &mImage ) )
120  {
121  mMode = RASTER;
122  }
123  else
124  {
125  mMode = Unknown;
126  }
127  }
128 
129  if ( mMode != Unknown ) //make sure we start with a new QImage
130  {
131  setSceneRect( QRectF( pos().x(), pos().y(), rect().width(), rect().height() ) );
132  }
133  emit itemChanged();
134 }
135 
136 QRectF QgsComposerPicture::boundedImageRect( double deviceWidth, double deviceHeight )
137 {
138  double imageToDeviceRatio;
139  if ( mImage.width() / deviceWidth > mImage.height() / deviceHeight )
140  {
141  imageToDeviceRatio = deviceWidth / mImage.width();
142  double height = imageToDeviceRatio * mImage.height();
143  return QRectF( 0, 0, deviceWidth, height );
144  }
145  else
146  {
147  imageToDeviceRatio = deviceHeight / mImage.height();
148  double width = imageToDeviceRatio * mImage.width();
149  return QRectF( 0, 0, width, deviceHeight );
150  }
151 }
152 
153 QRectF QgsComposerPicture::boundedSVGRect( double deviceWidth, double deviceHeight )
154 {
155  double imageToSvgRatio;
156  if ( deviceWidth / mDefaultSvgSize.width() > deviceHeight / mDefaultSvgSize.height() )
157  {
158  imageToSvgRatio = deviceHeight / mDefaultSvgSize.height();
159  double width = mDefaultSvgSize.width() * imageToSvgRatio;
160  return QRectF( 0, 0, width, deviceHeight );
161  }
162  else
163  {
164  imageToSvgRatio = deviceWidth / mDefaultSvgSize.width();
165  double height = mDefaultSvgSize.height() * imageToSvgRatio;
166  return QRectF( 0, 0, deviceWidth, height );
167  }
168 }
169 
171 {
172  if ( mMode == SVG )
173  {
174  return mDefaultSvgSize;
175  }
176  else if ( mMode == RASTER )
177  {
178  return QSizeF( mImage.width(), mImage.height() );
179  }
180  else
181  {
182  return QSizeF( 0, 0 );
183  }
184 }
185 
186 #if 0
187 QRectF QgsComposerPicture::boundedSVGRect( double deviceWidth, double deviceHeight )
188 {
189  double imageToSvgRatio;
190  if ( deviceWidth / mDefaultSvgSize.width() < deviceHeight / mDefaultSvgSize.height() )
191  {
192  imageToSvgRatio = deviceWidth / mDefaultSvgSize.width();
193  double height = mDefaultSvgSize.height() * imageToSvgRatio;
194  return QRectF( 0, 0, deviceWidth, height );
195  }
196  else
197  {
198  imageToSvgRatio = deviceHeight / mDefaultSvgSize.height();
199  double width = mDefaultSvgSize.width() * imageToSvgRatio;
200  return QRectF( 0, 0, width, deviceHeight );
201  }
202 }
203 #endif //0
204 
205 void QgsComposerPicture::setSceneRect( const QRectF& rectangle )
206 {
207  QgsComposerItem::setSceneRect( rectangle );
208 
209  //find largest scaling of picture with this rotation which fits in item
210  QSizeF currentPictureSize = pictureSize();
211  QRectF rotatedImageRect = largestRotatedRectWithinBounds( QRectF( 0, 0, currentPictureSize.width(), currentPictureSize.height() ), rectangle, mPictureRotation );
212  mPictureWidth = rotatedImageRect.width();
213  mPictureHeight = rotatedImageRect.height();
214 
215  emit itemChanged();
216 }
217 
219 {
220  //kept for compatibility for QGIS2.0 api
221  setPictureRotation( r );
222 }
223 
225 {
226  mPictureRotation = r;
227 
228  //find largest scaling of picture with this rotation which fits in item
229  QSizeF currentPictureSize = pictureSize();
230  QRectF rotatedImageRect = largestRotatedRectWithinBounds( QRectF( 0, 0, currentPictureSize.width(), currentPictureSize.height() ), rect(), mPictureRotation );
231  mPictureWidth = rotatedImageRect.width();
232  mPictureHeight = rotatedImageRect.height();
233 
234  update();
236 }
237 
238 void QgsComposerPicture::setRotationMap( int composerMapId )
239 {
240  if ( !mComposition )
241  {
242  return;
243  }
244 
245  if ( composerMapId == -1 ) //disable rotation from map
246  {
247  QObject::disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setPictureRotation( double ) ) );
248  mRotationMap = 0;
249  }
250 
251  const QgsComposerMap* map = mComposition->getComposerMapById( composerMapId );
252  if ( !map )
253  {
254  return;
255  }
256  if ( mRotationMap )
257  {
258  QObject::disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setPictureRotation( double ) ) );
259  }
260  mPictureRotation = map->mapRotation();
261  QObject::connect( map, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setPictureRotation( double ) ) );
262  mRotationMap = map;
263  update();
265 }
266 
268 {
269  return mSourceFile.fileName();
270 }
271 
272 bool QgsComposerPicture::writeXML( QDomElement& elem, QDomDocument & doc ) const
273 {
274  if ( elem.isNull() )
275  {
276  return false;
277  }
278  QDomElement composerPictureElem = doc.createElement( "ComposerPicture" );
279  composerPictureElem.setAttribute( "file", QgsProject::instance()->writePath( mSourceFile.fileName() ) );
280  composerPictureElem.setAttribute( "pictureWidth", QString::number( mPictureWidth ) );
281  composerPictureElem.setAttribute( "pictureHeight", QString::number( mPictureHeight ) );
282 
283  //rotation
284  composerPictureElem.setAttribute( "pictureRotation", QString::number( mPictureRotation ) );
285  if ( !mRotationMap )
286  {
287  composerPictureElem.setAttribute( "mapId", -1 );
288  }
289  else
290  {
291  composerPictureElem.setAttribute( "mapId", mRotationMap->id() );
292  }
293 
294  _writeXML( composerPictureElem, doc );
295  elem.appendChild( composerPictureElem );
296  return true;
297 }
298 
299 bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocument& doc )
300 {
301  if ( itemElem.isNull() )
302  {
303  return false;
304  }
305 
306  mPictureWidth = itemElem.attribute( "pictureWidth", "10" ).toDouble();
307  mPictureHeight = itemElem.attribute( "pictureHeight", "10" ).toDouble();
308 
309  QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
310  if ( composerItemList.size() > 0 )
311  {
312  QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
313 
314  if ( composerItemElem.attribute( "rotation", "0" ).toDouble() != 0 )
315  {
316  //in versions prior to 2.1 picture rotation was stored in the rotation attribute
317  mPictureRotation = composerItemElem.attribute( "rotation", "0" ).toDouble();
318  }
319 
320  _readXML( composerItemElem, doc );
321  }
322 
323  mDefaultSvgSize = QSize( 0, 0 );
324 
325  QString fileName = QgsProject::instance()->readPath( itemElem.attribute( "file" ) );
326  setPictureFile( fileName );
327 
328  //picture rotation
329  if ( itemElem.attribute( "pictureRotation", "0" ).toDouble() != 0 )
330  {
331  mPictureRotation = itemElem.attribute( "pictureRotation", "0" ).toDouble();
332  }
333 
334  //rotation map
335  int rotationMapId = itemElem.attribute( "mapId", "-1" ).toInt();
336  if ( rotationMapId == -1 )
337  {
338  mRotationMap = 0;
339  }
340  else if ( mComposition )
341  {
342 
343  if ( mRotationMap )
344  {
345  QObject::disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
346  }
347  mRotationMap = mComposition->getComposerMapById( rotationMapId );
348  QObject::connect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
349  }
350 
351  emit itemChanged();
352  return true;
353 }
354 
356 {
357  if ( !mRotationMap )
358  {
359  return -1;
360  }
361  else
362  {
363  return mRotationMap->id();
364  }
365 }
366 
367 bool QgsComposerPicture::imageSizeConsideringRotation( double& width, double& height ) const
368 {
369  //kept for api compatibility with QGIS 2.0 - use mPictureRotation
371 }
372 
373 bool QgsComposerPicture::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const
374 {
375  //kept for api compatibility with QGIS 2.0 - use mPictureRotation
377 }
378 
379 void QgsComposerPicture::sizeChangedByRotation( double& width, double& height )
380 {
381  //kept for api compatibility with QGIS 2.0 - use mPictureRotation
383 }
bool imageSizeConsideringRotation(double &width, double &height, double rotation) const
Calculates width and hight of the picture (in mm) such that it fits into the item frame with the give...
void setSceneRect(const QRectF &rectangle)
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
sets state from Dom document
QSizeF pictureSize()
Returns size of current raster or svg picture.
bool imageSizeConsideringRotation(double &width, double &height) const
Calculates width and hight of the picture (in mm) such that it fits into the item frame with the give...
A item that forms part of a map composition.
virtual void setRotation(double r)
Sets the picture rotation within the item bounds.
virtual void drawFrame(QPainter *p)
Draw black frame around item.
double mapRotation() const
Returns the rotation used for drawing the map within the composer item.
QString readPath(QString filename) const
turn filename read from the project file to an absolute path
void itemChanged()
Used e.g.
bool _readXML(const QDomElement &itemElem, const QDomDocument &doc)
Reads parameter that are not subclass specific in document.
QRectF boundedSVGRect(double deviceWidth, double deviceHeight)
Calculates bounding rect for svg file (mSourcefile) such that aspect ratio is correct.
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget)
Reimplementation of QCanvasItem::paint.
const QgsComposerMap * mRotationMap
Map that sets the rotation (or 0 if this picture uses map independent rotation)
virtual void drawSelectionBoxes(QPainter *p)
Draw selection boxes around item.
double mPictureHeight
Height of the picture (in mm)
QRectF largestRotatedRectWithinBounds(QRectF originalRect, QRectF boundsRect, double rotation) const
Calculates the largest scaled version of originalRect which fits within boundsRect, when it is rotated by a specified amount.
QgsComposition * mComposition
Graphics scene for map printing.
Object representing map window.
QString pictureFile() const
bool writeXML(QDomElement &elem, QDomDocument &doc) const
stores state in Dom element
bool cornerPointOnRotatedAndScaledRect(double &x, double &y, double width, double height) const
Calculates corner point after rotation and scaling.
void pictureRotationChanged(double newRotation)
Is emitted on picture rotation change.
int id() const
Get identification number.
void setPictureFile(const QString &path)
Sets the source file of the image (may be svg or a raster format)
bool cornerPointOnRotatedAndScaledRect(double &x, double &y, double width, double height, double rotation) const
Calculates corner point after rotation and scaling.
bool _writeXML(QDomElement &itemElem, QDomDocument &doc) const
Writes parameter that are not subclass specific in document.
virtual void drawBackground(QPainter *p)
Draw background.
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:362
virtual void setSceneRect(const QRectF &rectangle)
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
double mPictureWidth
Width of the picture (in mm)
void setRotationMap(int composerMapId)
Sets the map object for rotation (by id).
virtual void setPictureRotation(double r)
Sets the picture rotation within the item bounds.
double mPictureRotation
Image rotation.
int rotationMap() const
Returns the id of the rotation map.
QRectF boundedImageRect(double deviceWidth, double deviceHeight)
Calculates bounding rect for image such that aspect ratio is correct.
const QgsComposerMap * getComposerMapById(int id) const
Returns the composer map with specified id.
void sizeChangedByRotation(double &width, double &height, double rotation)
Calculates width / height of the bounding box of a rotated rectangle.
void sizeChangedByRotation(double &width, double &height)
Calculates width / height of the bounding box of a rotated rectangle.