1
/***************************************************************************
5
copyright : (C) 2005 by Radim Blazek
6
email : radim.blazek@gmail.com
7
***************************************************************************/
9
/***************************************************************************
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. *
16
***************************************************************************/
19
#include "qgscomposerpicture.h"
20
#include "qgscomposermap.h"
21
#include "qgsproject.h"
22
#include <QDomDocument>
23
#include <QDomElement>
25
#include <QImageReader>
27
#include <QSvgRenderer>
30
QgsComposerPicture::QgsComposerPicture( QgsComposition *composition ): QgsComposerItem( composition ), mMode( Unknown ), \
31
mSvgCacheUpToDate( false ), mCachedDpi( 0 ), mCachedRotation( 0 ), mCachedViewScaleFactor( -1 ), mRotationMap( 0 )
33
mPictureWidth = rect().width();
36
QgsComposerPicture::QgsComposerPicture(): QgsComposerItem( 0 ), mMode( Unknown ), mSvgCacheUpToDate( false ), mCachedRotation( 0 ), mCachedViewScaleFactor( -1 ), mRotationMap( 0 )
38
mPictureHeight = rect().height();
41
QgsComposerPicture::~QgsComposerPicture()
46
void QgsComposerPicture::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
53
drawBackground( painter );
55
int newDpi = ( painter->device()->logicalDpiX() + painter->device()->logicalDpiY() ) / 2;
56
double viewScaleFactor = horizontalViewScaleFactor();
58
if ( newDpi != mCachedDpi || mCachedRotation != mRotation || mCachedViewScaleFactor != viewScaleFactor )
60
mSvgCacheUpToDate = false;
63
if ( mMode != Unknown )
65
double rectPixelWidth = /*rect().width()*/mPictureWidth * newDpi / 25.4;
66
double rectPixelHeight = /*rect().height()*/ mPictureHeight * newDpi / 25.4;
70
boundRect = boundedSVGRect( rectPixelWidth, rectPixelHeight );
72
else if ( mMode == RASTER )
74
boundRect = boundedImageRect( rectPixelWidth, rectPixelHeight );
77
double boundRectWidthMM = boundRect.width() / newDpi * 25.4;
78
double boundRectHeightMM = boundRect.height() / newDpi * 25.4;
79
double boundImageWidth = boundRect.width();
80
double boundImageHeight = boundRect.height();
84
if ( !mSvgCacheUpToDate )
87
if ( mComposition && mComposition->plotStyle() == QgsComposition::Preview )
89
boundImageWidth *= std::min( viewScaleFactor, 10.0 );
90
boundImageHeight *= std::min( viewScaleFactor, 10.0 );
92
mImage = QImage( boundImageWidth, boundImageHeight, QImage::Format_ARGB32 );
98
painter->translate( rect().width() / 2.0, rect().height() / 2.0 );
99
painter->rotate( mRotation );
100
painter->translate( -boundRectWidthMM / 2.0, -boundRectHeightMM / 2.0 );
102
painter->drawImage( QRectF( 0, 0, boundRectWidthMM, boundRectHeightMM ), mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
108
mCachedRotation = mRotation;
109
mCachedViewScaleFactor = viewScaleFactor;
111
//frame and selection boxes
112
drawFrame( painter );
115
drawSelectionBoxes( painter );
119
void QgsComposerPicture::setPictureFile( const QString& path )
121
mSourceFile.setFileName( path );
122
if ( !mSourceFile.exists() )
127
QFileInfo sourceFileInfo( mSourceFile );
128
QString sourceFileSuffix = sourceFileInfo.suffix();
129
if ( sourceFileSuffix.compare( "svg", Qt::CaseInsensitive ) == 0 )
132
QSvgRenderer validTestRenderer( mSourceFile.fileName() );
133
if ( validTestRenderer.isValid() )
136
QRect viewBox = validTestRenderer.viewBox(); //take width/height ratio from view box instead of default size
137
mDefaultSvgSize.setWidth( viewBox.width() );
138
mDefaultSvgSize.setHeight( viewBox.height() );
139
mSvgCacheUpToDate = false;
148
//try to open raster with QImageReader
149
QImageReader imageReader( mSourceFile.fileName() );
150
if ( imageReader.read( &mImage ) )
160
if ( mMode != Unknown ) //make sure we start with a new QImage
162
setSceneRect( QRectF( transform().dx(), transform().dy(), rect().width(), rect().height() ) );
164
emit settingsChanged();
167
QRectF QgsComposerPicture::boundedImageRect( double deviceWidth, double deviceHeight )
169
double imageToDeviceRatio;
170
if ( mImage.width() / deviceWidth > mImage.height() / deviceHeight )
172
imageToDeviceRatio = deviceWidth / mImage.width();
173
double height = imageToDeviceRatio * mImage.height();
174
return QRectF( 0, 0, deviceWidth, height );
178
imageToDeviceRatio = deviceHeight / mImage.height();
179
double width = imageToDeviceRatio * mImage.width();
180
return QRectF( 0, 0, width, deviceHeight );
184
QRectF QgsComposerPicture::boundedSVGRect( double deviceWidth, double deviceHeight )
186
double imageToSvgRatio;
187
if ( deviceWidth / mDefaultSvgSize.width() > deviceHeight / mDefaultSvgSize.height() )
189
imageToSvgRatio = deviceHeight / mDefaultSvgSize.height();
190
double width = mDefaultSvgSize.width() * imageToSvgRatio;
191
return QRectF( 0, 0, width, deviceHeight );
195
imageToSvgRatio = deviceWidth / mDefaultSvgSize.width();
196
double height = mDefaultSvgSize.height() * imageToSvgRatio;
197
return QRectF( 0, 0, deviceWidth, height );
202
QRectF QgsComposerPicture::boundedSVGRect( double deviceWidth, double deviceHeight )
204
double imageToSvgRatio;
205
if ( deviceWidth / mDefaultSvgSize.width() < deviceHeight / mDefaultSvgSize.height() )
207
imageToSvgRatio = deviceWidth / mDefaultSvgSize.width();
208
double height = mDefaultSvgSize.height() * imageToSvgRatio;
209
return QRectF( 0, 0, deviceWidth, height );
213
imageToSvgRatio = deviceHeight / mDefaultSvgSize.height();
214
double width = mDefaultSvgSize.width() * imageToSvgRatio;
215
return QRectF( 0, 0, width, deviceHeight );
220
void QgsComposerPicture::updateImageFromSvg()
223
QPainter p( &mImage );
224
p.setRenderHints( QPainter::Antialiasing | QPainter::TextAntialiasing, true );
225
QSvgRenderer theRenderer( mSourceFile.fileName() );
226
theRenderer.render( &p );
227
mSvgCacheUpToDate = true;
232
void QgsComposerPicture::setSceneRect( const QRectF& rectangle )
234
mSvgCacheUpToDate = false;
235
QgsComposerItem::setSceneRect( rectangle );
237
//consider to change size of the shape if the rectangle changes width and/or height
238
double newPictureWidth = rectangle.width();
239
double newPictureHeight = rectangle.height();
240
imageSizeConsideringRotation( newPictureWidth, newPictureHeight );
241
mPictureWidth = newPictureWidth;
242
mPictureHeight = newPictureHeight;
244
emit settingsChanged();
247
void QgsComposerPicture::setRotation( double r )
249
//adapt rectangle size
250
double width = mPictureWidth;
251
double height = mPictureHeight;
252
sizeChangedByRotation( width, height );
254
//adapt scene rect to have the same center and the new width / height
255
double x = transform().dx() + rect().width() / 2.0 - width / 2.0;
256
double y = transform().dy() + rect().height() / 2.0 - height / 2.0;
257
QgsComposerItem::setSceneRect( QRectF( x, y, width, height ) );
259
QgsComposerItem::setRotation( r );
262
void QgsComposerPicture::setRotationMap( int composerMapId )
269
if ( composerMapId == -1 ) //disable rotation from map
271
QObject::disconnect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
275
const QgsComposerMap* map = mComposition->getComposerMapById( composerMapId );
282
QObject::disconnect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
284
mRotation = map->rotation();
285
QObject::connect( map, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
287
setRotation( map->rotation() );
290
QString QgsComposerPicture::pictureFile() const
292
return mSourceFile.fileName();
295
bool QgsComposerPicture::writeXML( QDomElement& elem, QDomDocument & doc ) const
301
QDomElement composerPictureElem = doc.createElement( "ComposerPicture" );
302
composerPictureElem.setAttribute( "file", QgsProject::instance()->writePath( mSourceFile.fileName() ) );
303
composerPictureElem.setAttribute( "pictureWidth", mPictureWidth );
304
composerPictureElem.setAttribute( "pictureHeight", mPictureHeight );
307
composerPictureElem.setAttribute( "mapId", -1 );
311
composerPictureElem.setAttribute( "mapId", mRotationMap->id() );
314
_writeXML( composerPictureElem, doc );
315
elem.appendChild( composerPictureElem );
319
bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocument& doc )
321
if ( itemElem.isNull() )
326
mPictureWidth = itemElem.attribute( "pictureWidth", "10" ).toDouble();
327
mPictureHeight = itemElem.attribute( "pictureHeight", "10" ).toDouble();
329
QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
330
if ( composerItemList.size() > 0 )
332
_readXML( composerItemList.at( 0 ).toElement(), doc );
336
mSvgCacheUpToDate = false;
337
mDefaultSvgSize = QSize( 0, 0 );
340
QString fileName = QgsProject::instance()->readPath( itemElem.attribute( "file" ) );
341
setPictureFile( fileName );
344
int rotationMapId = itemElem.attribute( "mapId", "-1" ).toInt();
345
if ( rotationMapId == -1 )
349
else if ( mComposition )
354
QObject::disconnect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
356
mRotationMap = mComposition->getComposerMapById( rotationMapId );
357
QObject::connect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
363
int QgsComposerPicture::rotationMap() const
371
return mRotationMap->id();