@@ -38,6 +38,7 @@ QgsComposerPicture::QgsComposerPicture( QgsComposition *composition ) :
3838 mPictureRotation( 0 ),
3939 mRotationMap( 0 ),
4040 mResizeMode( QgsComposerPicture::Zoom ),
41+ mPictureAnchor( UpperLeft ),
4142 mPictureExpr( 0 )
4243{
4344 mPictureWidth = rect ().width ();
@@ -50,6 +51,7 @@ QgsComposerPicture::QgsComposerPicture() : QgsComposerItem( 0 ),
5051 mPictureRotation( 0 ),
5152 mRotationMap( 0 ),
5253 mResizeMode( QgsComposerPicture::Zoom ),
54+ mPictureAnchor( UpperLeft ),
5355 mPictureExpr( 0 )
5456{
5557 mPictureHeight = rect ().height ();
@@ -90,40 +92,99 @@ void QgsComposerPicture::paint( QPainter* painter, const QStyleOptionGraphicsIte
9092
9193 // int newDpi = ( painter->device()->logicalDpiX() + painter->device()->logicalDpiY() ) / 2;
9294
95+ // picture resizing
9396 if ( mMode != Unknown )
9497 {
9598 double boundRectWidthMM;
9699 double boundRectHeightMM;
97- double imageRectWidthMM;
98- double imageRectHeightMM;
100+ QRect imageRect;
99101 if ( mResizeMode == QgsComposerPicture::Zoom || mResizeMode == QgsComposerPicture::ZoomResizeFrame )
100102 {
101103 boundRectWidthMM = mPictureWidth ;
102104 boundRectHeightMM = mPictureHeight ;
103- imageRectWidthMM = mImage .width ();
104- imageRectHeightMM = mImage .height ();
105+ imageRect = QRect ( 0 , 0 , mImage .width (), mImage .height () );
105106 }
106107 else if ( mResizeMode == QgsComposerPicture::Stretch )
107108 {
108109 boundRectWidthMM = rect ().width ();
109110 boundRectHeightMM = rect ().height ();
110- imageRectWidthMM = mImage .width ();
111- imageRectHeightMM = mImage .height ();
111+ imageRect = QRect ( 0 , 0 , mImage .width (), mImage .height () );
112+ }
113+ else if ( mResizeMode == QgsComposerPicture::Clip )
114+ {
115+ boundRectWidthMM = rect ().width ();
116+ boundRectHeightMM = rect ().height ();
117+ int imageRectWidthPixels = mImage .width ();
118+ int imageRectHeightPixels = mImage .height ();
119+ imageRect = clippedImageRect ( boundRectWidthMM, boundRectHeightMM ,
120+ QSize ( imageRectWidthPixels, imageRectHeightPixels ) );
112121 }
113122 else
114123 {
115124 boundRectWidthMM = rect ().width ();
116125 boundRectHeightMM = rect ().height ();
117- imageRectWidthMM = rect ().width () * mComposition ->printResolution () / 25.4 ;
118- imageRectHeightMM = rect ().height () * mComposition ->printResolution () / 25.4 ;
126+ imageRect = QRect ( 0 , 0 , rect ().width () * mComposition ->printResolution () / 25.4 ,
127+ rect ().height () * mComposition ->printResolution () / 25.4 ) ;
119128 }
120129 painter->save ();
121130
131+ // zoom mode - calculate anchor point and rotation
122132 if ( mResizeMode == Zoom )
123133 {
124- painter->translate ( rect ().width () / 2.0 , rect ().height () / 2.0 );
125- painter->rotate ( mPictureRotation );
126- painter->translate ( -boundRectWidthMM / 2.0 , -boundRectHeightMM / 2.0 );
134+ // TODO - allow placement modes with rotation set. for now, setting a rotation
135+ // always places picture in center of frame
136+ if ( mPictureRotation != 0 )
137+ {
138+ painter->translate ( rect ().width () / 2.0 , rect ().height () / 2.0 );
139+ painter->rotate ( mPictureRotation );
140+ painter->translate ( -boundRectWidthMM / 2.0 , -boundRectHeightMM / 2.0 );
141+ }
142+ else
143+ {
144+ // shift painter to edge/middle of frame depending on placement
145+ double diffX = rect ().width () - boundRectWidthMM;
146+ double diffY = rect ().height () - boundRectHeightMM;
147+
148+ double dX = 0 ;
149+ double dY = 0 ;
150+ switch ( mPictureAnchor )
151+ {
152+ case UpperLeft:
153+ case MiddleLeft:
154+ case LowerLeft:
155+ // nothing to do
156+ break ;
157+ case UpperMiddle:
158+ case Middle:
159+ case LowerMiddle:
160+ dX = diffX / 2.0 ;
161+ break ;
162+ case UpperRight:
163+ case MiddleRight:
164+ case LowerRight:
165+ dX = diffX;
166+ break ;
167+ }
168+ switch ( mPictureAnchor )
169+ {
170+ case UpperLeft:
171+ case UpperMiddle:
172+ case UpperRight:
173+ // nothing to do
174+ break ;
175+ case MiddleLeft:
176+ case Middle:
177+ case MiddleRight:
178+ dY = diffY / 2.0 ;
179+ break ;
180+ case LowerLeft:
181+ case LowerMiddle:
182+ case LowerRight:
183+ dY = diffY;
184+ break ;
185+ }
186+ painter->translate ( dX, dY );
187+ }
127188 }
128189
129190 if ( mMode == SVG )
@@ -132,7 +193,7 @@ void QgsComposerPicture::paint( QPainter* painter, const QStyleOptionGraphicsIte
132193 }
133194 else if ( mMode == RASTER )
134195 {
135- painter->drawImage ( QRectF ( 0 , 0 , boundRectWidthMM, boundRectHeightMM ), mImage , QRectF ( 0 , 0 , imageRectWidthMM, imageRectHeightMM ) );
196+ painter->drawImage ( QRectF ( 0 , 0 , boundRectWidthMM, boundRectHeightMM ), mImage , imageRect );
136197 }
137198
138199 painter->restore ();
@@ -146,6 +207,64 @@ void QgsComposerPicture::paint( QPainter* painter, const QStyleOptionGraphicsIte
146207 }
147208}
148209
210+ QRect QgsComposerPicture::clippedImageRect ( double &boundRectWidthMM, double &boundRectHeightMM, QSize imageRectPixels )
211+ {
212+ int boundRectWidthPixels = boundRectWidthMM * mComposition ->printResolution () / 25.4 ;
213+ int boundRectHeightPixels = boundRectHeightMM * mComposition ->printResolution () / 25.4 ;
214+
215+ // update boundRectWidth/Height so that they exactly match pixel bounds
216+ boundRectWidthMM = boundRectWidthPixels * 25.4 / mComposition ->printResolution ();
217+ boundRectHeightMM = boundRectHeightPixels * 25.4 / mComposition ->printResolution ();
218+
219+ // calculate part of image which fits in bounds
220+ int leftClip = 0 ;
221+ int topClip = 0 ;
222+
223+ // calculate left crop
224+ switch ( mPictureAnchor )
225+ {
226+ case UpperLeft:
227+ case MiddleLeft:
228+ case LowerLeft:
229+ leftClip = 0 ;
230+ break ;
231+ case UpperMiddle:
232+ case Middle:
233+ case LowerMiddle:
234+ leftClip = ( imageRectPixels.width () - boundRectWidthPixels ) / 2 ;
235+ break ;
236+ case UpperRight:
237+ case MiddleRight:
238+ case LowerRight:
239+ leftClip = imageRectPixels.width () - boundRectWidthPixels;
240+ break ;
241+ }
242+
243+ // calculate top crop
244+ switch ( mPictureAnchor )
245+ {
246+ case UpperLeft:
247+ case UpperMiddle:
248+ case UpperRight:
249+ topClip = 0 ;
250+ break ;
251+ case MiddleLeft:
252+ case Middle:
253+ case MiddleRight:
254+ topClip = ( imageRectPixels.height () - boundRectHeightPixels ) / 2 ;
255+ break ;
256+ case LowerLeft:
257+ case LowerMiddle:
258+ case LowerRight:
259+ topClip = imageRectPixels.height () - boundRectHeightPixels;
260+ break ;
261+ }
262+
263+
264+ return QRect ( leftClip, topClip, boundRectWidthPixels, boundRectHeightPixels );
265+
266+ }
267+
149268void QgsComposerPicture::setPictureFile ( const QString& path )
150269{
151270 mSourceFile .setFileName ( path );
@@ -525,6 +644,8 @@ bool QgsComposerPicture::writeXML( QDomElement& elem, QDomDocument & doc ) const
525644 composerPictureElem.setAttribute ( " pictureWidth" , QString::number ( mPictureWidth ) );
526645 composerPictureElem.setAttribute ( " pictureHeight" , QString::number ( mPictureHeight ) );
527646 composerPictureElem.setAttribute ( " resizeMode" , QString::number (( int )mResizeMode ) );
647+ composerPictureElem.setAttribute ( " anchorPoint" , QString::number (( int )mPictureAnchor ) );
648+
528649 if ( mUseSourceExpression )
529650 {
530651 composerPictureElem.setAttribute ( " useExpression" , " true" );
@@ -561,6 +682,7 @@ bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocumen
561682 mPictureWidth = itemElem.attribute ( " pictureWidth" , " 10" ).toDouble ();
562683 mPictureHeight = itemElem.attribute ( " pictureHeight" , " 10" ).toDouble ();
563684 mResizeMode = QgsComposerPicture::ResizeMode ( itemElem.attribute ( " resizeMode" , " 0" ).toInt () );
685+ mPictureAnchor = QgsComposerItem::ItemPositionMode ( itemElem.attribute ( " anchorPoint" , QString ( QgsComposerItem::UpperLeft ) ).toInt () );
564686
565687 QDomNodeList composerItemList = itemElem.elementsByTagName ( " ComposerItem" );
566688 if ( composerItemList.size () > 0 )
@@ -594,8 +716,6 @@ bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocumen
594716 QString fileName = QgsProject::instance ()->readPath ( itemElem.attribute ( " file" ) );
595717 mSourceFile .setFileName ( fileName );
596718
597- refreshPicture ();
598-
599719 // picture rotation
600720 if ( itemElem.attribute ( " pictureRotation" , " 0" ).toDouble () != 0 )
601721 {
@@ -619,6 +739,8 @@ bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocumen
619739 QObject::connect ( mRotationMap , SIGNAL ( mapRotationChanged ( double ) ), this , SLOT ( setRotation ( double ) ) );
620740 }
621741
742+ refreshPicture ();
743+
622744 emit itemChanged ();
623745 return true ;
624746}
@@ -635,6 +757,12 @@ int QgsComposerPicture::rotationMap() const
635757 }
636758}
637759
760+ void QgsComposerPicture::setPictureAnchor ( QgsComposerItem::ItemPositionMode anchor )
761+ {
762+ mPictureAnchor = anchor;
763+ update ();
764+ }
765+
638766bool QgsComposerPicture::imageSizeConsideringRotation ( double & width, double & height ) const
639767{
640768 // kept for api compatibility with QGIS 2.0 - use mPictureRotation
0 commit comments