Skip to content

Commit 23b660e

Browse files
committedApr 28, 2014
[FEATURE][composer] Implement different resize modes for composer picture items, including zoom, stretch, clip, frame to image size (fix #7886). (Sponsored by City of Uster, Switzerland)
1 parent 8ab3ce4 commit 23b660e

File tree

5 files changed

+190
-28
lines changed

5 files changed

+190
-28
lines changed
 

‎src/app/composer/qgscomposerpicturewidget.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,21 @@ void QgsComposerPictureWidget::on_mRemoveDirectoryButton_clicked()
198198
s.setValue( "/Composer/PictureWidgetDirectories", userDirList );
199199
}
200200

201+
void QgsComposerPictureWidget::on_mResizeModeComboBox_currentIndexChanged( int index )
202+
{
203+
if ( !mPicture )
204+
{
205+
return;
206+
}
207+
208+
mPicture->beginCommand( tr( "Picture resize mode changed" ) );
209+
mPicture->setResizeMode(( QgsComposerPicture::ResizeMode )index );
210+
mPicture->endCommand();
211+
212+
//disable picture rotation for non-zoom modes
213+
mRotationGroupBox->setEnabled( mPicture->resizeMode() == QgsComposerPicture::Zoom );
214+
}
215+
201216
void QgsComposerPictureWidget::on_mRotationFromComposerMapCheckBox_stateChanged( int state )
202217
{
203218
if ( !mPicture )
@@ -326,6 +341,7 @@ void QgsComposerPictureWidget::setGuiElementValues()
326341
mPictureLineEdit->blockSignals( true );
327342
mComposerMapComboBox->blockSignals( true );
328343
mRotationFromComposerMapCheckBox->blockSignals( true );
344+
mResizeModeComboBox->blockSignals( true );
329345

330346
mPictureLineEdit->setText( mPicture->pictureFile() );
331347
// QRectF pictureRect = mPicture->rect();
@@ -352,11 +368,15 @@ void QgsComposerPictureWidget::setGuiElementValues()
352368
mComposerMapComboBox->setEnabled( false );
353369
}
354370

371+
mResizeModeComboBox->setCurrentIndex(( int )mPicture->resizeMode() );
372+
//disable picture rotation for non-zoom modes
373+
mRotationGroupBox->setEnabled( mPicture->resizeMode() == QgsComposerPicture::Zoom );
355374

356375
mRotationFromComposerMapCheckBox->blockSignals( false );
357376
mPictureRotationSpinBox->blockSignals( false );
358377
mPictureLineEdit->blockSignals( false );
359378
mComposerMapComboBox->blockSignals( false );
379+
mResizeModeComboBox->blockSignals( false );
360380
}
361381
}
362382

‎src/app/composer/qgscomposerpicturewidget.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class QgsComposerPictureWidget: public QWidget, private Ui::QgsComposerPictureWi
4545
void on_mRemoveDirectoryButton_clicked();
4646
void on_mRotationFromComposerMapCheckBox_stateChanged( int state );
4747
void on_mComposerMapComboBox_activated( const QString & text );
48+
void on_mResizeModeComboBox_currentIndexChanged( int index );
4849

4950
protected:
5051
void showEvent( QShowEvent * event );

‎src/core/composer/qgscomposerpicture.cpp

Lines changed: 103 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,13 @@
2828

2929

3030
QgsComposerPicture::QgsComposerPicture( QgsComposition *composition )
31-
: QgsComposerItem( composition ), mMode( Unknown ), mPictureRotation( 0 ), mRotationMap( 0 )
31+
: QgsComposerItem( composition ), mMode( Unknown ), mPictureRotation( 0 ), mRotationMap( 0 ),
32+
mResizeMode( QgsComposerPicture::Zoom )
3233
{
3334
mPictureWidth = rect().width();
3435
}
3536

36-
QgsComposerPicture::QgsComposerPicture(): QgsComposerItem( 0 ), mMode( Unknown ), mPictureRotation( 0 ), mRotationMap( 0 )
37+
QgsComposerPicture::QgsComposerPicture(): QgsComposerItem( 0 ), mMode( Unknown ), mPictureRotation( 0 ), mRotationMap( 0 ), mResizeMode( QgsComposerPicture::Zoom )
3738
{
3839
mPictureHeight = rect().height();
3940
}
@@ -58,21 +59,47 @@ void QgsComposerPicture::paint( QPainter* painter, const QStyleOptionGraphicsIte
5859

5960
if ( mMode != Unknown )
6061
{
61-
double boundRectWidthMM = mPictureWidth;
62-
double boundRectHeightMM = mPictureHeight;
63-
62+
double boundRectWidthMM;
63+
double boundRectHeightMM;
64+
double imageRectWidthMM;
65+
double imageRectHeightMM;
66+
if ( mResizeMode == QgsComposerPicture::Zoom || mResizeMode == QgsComposerPicture::ZoomResizeFrame )
67+
{
68+
boundRectWidthMM = mPictureWidth;
69+
boundRectHeightMM = mPictureHeight;
70+
imageRectWidthMM = mImage.width();
71+
imageRectHeightMM = mImage.height();
72+
}
73+
else if ( mResizeMode == QgsComposerPicture::Stretch )
74+
{
75+
boundRectWidthMM = rect().width();
76+
boundRectHeightMM = rect().height();
77+
imageRectWidthMM = mImage.width();
78+
imageRectHeightMM = mImage.height();
79+
}
80+
else
81+
{
82+
boundRectWidthMM = rect().width();
83+
boundRectHeightMM = rect().height();
84+
imageRectWidthMM = rect().width() * mComposition->printResolution() / 25.4;
85+
imageRectHeightMM = rect().height() * mComposition->printResolution() / 25.4;
86+
}
6487
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 );
88+
89+
if ( mResizeMode == Zoom )
90+
{
91+
painter->translate( rect().width() / 2.0, rect().height() / 2.0 );
92+
painter->rotate( mPictureRotation );
93+
painter->translate( -boundRectWidthMM / 2.0, -boundRectHeightMM / 2.0 );
94+
}
6895

6996
if ( mMode == SVG )
7097
{
7198
mSVG.render( painter, QRectF( 0, 0, boundRectWidthMM, boundRectHeightMM ) );
7299
}
73100
else if ( mMode == RASTER )
74101
{
75-
painter->drawImage( QRectF( 0, 0, boundRectWidthMM, boundRectHeightMM ), mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
102+
painter->drawImage( QRectF( 0, 0, boundRectWidthMM, boundRectHeightMM ), mImage, QRectF( 0, 0, imageRectWidthMM, imageRectHeightMM ) );
76103
}
77104

78105
painter->restore();
@@ -204,14 +231,53 @@ QRectF QgsComposerPicture::boundedSVGRect( double deviceWidth, double deviceHeig
204231

205232
void QgsComposerPicture::setSceneRect( const QRectF& rectangle )
206233
{
207-
QgsComposerItem::setSceneRect( rectangle );
208234

209-
//find largest scaling of picture with this rotation which fits in item
210235
QSizeF currentPictureSize = pictureSize();
211-
QRectF rotatedImageRect = largestRotatedRectWithinBounds( QRectF( 0, 0, currentPictureSize.width(), currentPictureSize.height() ), rectangle, mPictureRotation );
212-
mPictureWidth = rotatedImageRect.width();
213-
mPictureHeight = rotatedImageRect.height();
214236

237+
if ( mResizeMode == QgsComposerPicture::Clip )
238+
{
239+
QgsComposerItem::setSceneRect( rectangle );
240+
mPictureWidth = rectangle.width();
241+
mPictureHeight = rectangle.height();
242+
return;
243+
}
244+
245+
QRectF newRect = rectangle;
246+
247+
if ( mResizeMode == ZoomResizeFrame && !rect().isEmpty() )
248+
{
249+
//if width has changed less than height, then fix width and set height correspondingly
250+
//else, do the opposite
251+
if ( qAbs( rect().width() - rectangle.width() ) <
252+
qAbs( rect().height() - rectangle.height() ) )
253+
{
254+
newRect.setHeight( currentPictureSize.height() * newRect.width() / currentPictureSize.width() );
255+
}
256+
else
257+
{
258+
newRect.setWidth( currentPictureSize.width() * newRect.height() / currentPictureSize.height() );
259+
}
260+
}
261+
else if ( mResizeMode == FrameToImageSize )
262+
{
263+
newRect.setWidth( currentPictureSize.width() * 25.4 / mComposition->printResolution() );
264+
newRect.setHeight( currentPictureSize.height() * 25.4 / mComposition->printResolution() );
265+
}
266+
267+
//find largest scaling of picture with this rotation which fits in item
268+
if ( mResizeMode == Zoom )
269+
{
270+
QRectF rotatedImageRect = largestRotatedRectWithinBounds( QRectF( 0, 0, currentPictureSize.width(), currentPictureSize.height() ), newRect, mPictureRotation );
271+
mPictureWidth = rotatedImageRect.width();
272+
mPictureHeight = rotatedImageRect.height();
273+
}
274+
else
275+
{
276+
mPictureWidth = newRect.width();
277+
mPictureHeight = newRect.height();
278+
}
279+
280+
QgsComposerItem::setSceneRect( newRect );
215281
emit itemChanged();
216282
}
217283

@@ -225,13 +291,16 @@ void QgsComposerPicture::setPictureRotation( double r )
225291
{
226292
mPictureRotation = r;
227293

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();
294+
if ( mResizeMode == Zoom )
295+
{
296+
//find largest scaling of picture with this rotation which fits in item
297+
QSizeF currentPictureSize = pictureSize();
298+
QRectF rotatedImageRect = largestRotatedRectWithinBounds( QRectF( 0, 0, currentPictureSize.width(), currentPictureSize.height() ), rect(), mPictureRotation );
299+
mPictureWidth = rotatedImageRect.width();
300+
mPictureHeight = rotatedImageRect.height();
301+
update();
302+
}
233303

234-
update();
235304
emit pictureRotationChanged( mPictureRotation );
236305
}
237306

@@ -264,6 +333,18 @@ void QgsComposerPicture::setRotationMap( int composerMapId )
264333
emit pictureRotationChanged( mPictureRotation );
265334
}
266335

336+
void QgsComposerPicture::setResizeMode( QgsComposerPicture::ResizeMode mode )
337+
{
338+
mResizeMode = mode;
339+
if ( mode == QgsComposerPicture::ZoomResizeFrame || mode == QgsComposerPicture::FrameToImageSize
340+
|| ( mode == QgsComposerPicture::Zoom && mPictureRotation != 0 ) )
341+
{
342+
//call set scene rect to force item to resize to fit picture
343+
setSceneRect( QRectF( pos().x(), pos().y(), rect().width(), rect().height() ) );
344+
}
345+
update();
346+
}
347+
267348
QString QgsComposerPicture::pictureFile() const
268349
{
269350
return mSourceFile.fileName();
@@ -279,6 +360,7 @@ bool QgsComposerPicture::writeXML( QDomElement& elem, QDomDocument & doc ) const
279360
composerPictureElem.setAttribute( "file", QgsProject::instance()->writePath( mSourceFile.fileName() ) );
280361
composerPictureElem.setAttribute( "pictureWidth", QString::number( mPictureWidth ) );
281362
composerPictureElem.setAttribute( "pictureHeight", QString::number( mPictureHeight ) );
363+
composerPictureElem.setAttribute( "resizeMode", QString::number(( int )mResizeMode ) );
282364

283365
//rotation
284366
composerPictureElem.setAttribute( "pictureRotation", QString::number( mPictureRotation ) );
@@ -305,6 +387,7 @@ bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocumen
305387

306388
mPictureWidth = itemElem.attribute( "pictureWidth", "10" ).toDouble();
307389
mPictureHeight = itemElem.attribute( "pictureHeight", "10" ).toDouble();
390+
mResizeMode = QgsComposerPicture::ResizeMode( itemElem.attribute( "resizeMode", "0" ).toInt() );
308391

309392
QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
310393
if ( composerItemList.size() > 0 )

‎src/core/composer/qgscomposerpicture.h

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,23 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
3131
{
3232
Q_OBJECT
3333
public:
34+
35+
enum ResizeMode
36+
{
37+
Zoom,
38+
Stretch,
39+
Clip,
40+
ZoomResizeFrame,
41+
FrameToImageSize
42+
};
43+
44+
enum Mode //SVG or raster graphic format
45+
{
46+
SVG,
47+
RASTER,
48+
Unknown
49+
};
50+
3451
QgsComposerPicture( QgsComposition *composition );
3552
~QgsComposerPicture();
3653

@@ -76,6 +93,10 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
7693
/**True if the rotation is taken from a map item*/
7794
bool useRotationMap() const {return mRotationMap;}
7895

96+
/**Returns the resize mode used for drawing the picture within the composer item
97+
*/
98+
ResizeMode resizeMode() const { return mResizeMode;};
99+
79100
/**Calculates width and hight of the picture (in mm) such that it fits into the item frame with the given rotation
80101
* @deprecated Use bool QgsComposerItem::imageSizeConsideringRotation( double& width, double& height, double rotation )
81102
* instead
@@ -92,6 +113,8 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
92113
*/
93114
Q_DECL_DEPRECATED void sizeChangedByRotation( double& width, double& height );
94115

116+
Mode mode() const { return mMode; };
117+
95118
public slots:
96119
/**Sets the picture rotation within the item bounds. This does not affect the item rectangle,
97120
only the way the picture is drawn within the item.
@@ -104,19 +127,16 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
104127
@note this function was added in version 2.1*/
105128
virtual void setPictureRotation( double r );
106129

130+
/**Sets the resize mode used for drawing the picture within the item bounds
131+
@note this function was added in version 2.1*/
132+
virtual void setResizeMode( ResizeMode mode );
133+
107134
signals:
108135
/**Is emitted on picture rotation change*/
109136
void pictureRotationChanged( double newRotation );
110137

111138
private:
112139

113-
enum Mode //SVG or raster graphic format
114-
{
115-
SVG,
116-
RASTER,
117-
Unknown
118-
};
119-
120140
//default constructor is forbidden
121141
QgsComposerPicture();
122142
/**Calculates bounding rect for svg file (mSourcefile) such that aspect ratio is correct*/
@@ -142,6 +162,8 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
142162
double mPictureWidth;
143163
/**Height of the picture (in mm)*/
144164
double mPictureHeight;
165+
166+
ResizeMode mResizeMode;
145167
};
146168

147169
#endif

‎src/ui/qgscomposerpicturewidgetbase.ui

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,42 @@
105105
</item>
106106
</layout>
107107
</item>
108+
<item>
109+
<widget class="QLabel" name="label_4">
110+
<property name="text">
111+
<string>Resize mode</string>
112+
</property>
113+
</widget>
114+
</item>
115+
<item>
116+
<widget class="QComboBox" name="mResizeModeComboBox">
117+
<item>
118+
<property name="text">
119+
<string>Zoom</string>
120+
</property>
121+
</item>
122+
<item>
123+
<property name="text">
124+
<string>Stretch</string>
125+
</property>
126+
</item>
127+
<item>
128+
<property name="text">
129+
<string>Clip</string>
130+
</property>
131+
</item>
132+
<item>
133+
<property name="text">
134+
<string>Zoom and resize frame</string>
135+
</property>
136+
</item>
137+
<item>
138+
<property name="text">
139+
<string>Resize frame to image size</string>
140+
</property>
141+
</item>
142+
</widget>
143+
</item>
108144
</layout>
109145
</widget>
110146
</item>
@@ -211,7 +247,7 @@
211247
</widget>
212248
</item>
213249
<item>
214-
<widget class="QgsCollapsibleGroupBoxBasic" name="groupBox">
250+
<widget class="QgsCollapsibleGroupBoxBasic" name="mRotationGroupBox">
215251
<property name="title">
216252
<string>Image rotation</string>
217253
</property>

0 commit comments

Comments
 (0)
Please sign in to comment.