@@ -147,13 +147,30 @@ void QgsWMSServer::executeRequest()
147
147
}
148
148
149
149
// version
150
- QString version = mParameters .value ( " VERSION" , " 1.3.0" );
150
+ QString version = " 1.3.0" ;
151
+ if ( mParameters .contains ( " VERSION" ) )
152
+ {
153
+ version = mParameters .value ( " VERSION" );
154
+ }
155
+ else if ( mParameters .contains ( " WMTVER" ) ) // WMTVER needs to be supported by WMS 1.1.1 for backwards compatibility with WMS 1.0.0
156
+ {
157
+ version = mParameters .value ( " WMTVER" );
158
+ }
159
+
151
160
bool getProjectSettings = ( request.compare ( " GetProjectSettings" , Qt::CaseInsensitive ) == 0 );
152
161
if ( getProjectSettings )
153
162
{
154
163
version = " 1.3.0" ; // getProjectSettings extends WMS 1.3.0 capabilities
155
164
}
156
165
166
+ if ( version == " 1.1.1" )
167
+ {
168
+ if ( request.compare ( " capabilities" , Qt::CaseInsensitive ) == 0 )
169
+ {
170
+ request = QString ( " GetCapabilities" );
171
+ }
172
+ }
173
+
157
174
// GetCapabilities
158
175
if ( request.compare ( " GetCapabilities" , Qt::CaseInsensitive ) == 0 || getProjectSettings )
159
176
{
@@ -423,6 +440,12 @@ QDomDocument QgsWMSServer::getCapabilities( QString version, bool fullProjectInf
423
440
hrefString = serviceUrl ();
424
441
}
425
442
443
+ // href needs to be a prefix
444
+ if ( !hrefString.endsWith ( " ?" ) && !hrefString.endsWith ( " &" ) )
445
+ {
446
+ hrefString.append ( hrefString.contains ( " ?" ) ? " &" : " ?" );
447
+ }
448
+
426
449
if ( version == " 1.1.1" )
427
450
{
428
451
doc = QDomDocument ( " WMT_MS_Capabilities SYSTEM 'http://schemas.opengis.net/wms/1.1.1/WMS_MS_Capabilities.dtd'" ); // WMS 1.1.1 needs DOCTYPE "SYSTEM http://schemas.opengis.net/wms/1.1.1/WMS_MS_Capabilities.dtd"
@@ -556,7 +579,7 @@ QDomDocument QgsWMSServer::getCapabilities( QString version, bool fullProjectInf
556
579
557
580
// Exception element is mandatory
558
581
elem = doc.createElement ( " Exception" );
559
- appendFormats ( doc, elem, QStringList () << ( version == " 1.1.1" ? " application/vnd.ogc.se_xml" : " text/xml " ) );
582
+ appendFormats ( doc, elem, QStringList () << ( version == " 1.1.1" ? " application/vnd.ogc.se_xml" : " XML " ) );
560
583
capabilityElement.appendChild ( elem );
561
584
562
585
// UserDefinedSymbolization element
@@ -690,6 +713,10 @@ static QgsRectangle _parseBBOX( const QString &bboxStr, bool &ok )
690
713
}
691
714
692
715
ok = true ;
716
+ if ( d[2 ] <= d[0 ] || d[3 ] <= d[1 ] )
717
+ {
718
+ throw QgsMapServiceException ( " InvalidParameterValue" , " BBOX is empty" );
719
+ }
693
720
return QgsRectangle ( d[0 ], d[1 ], d[2 ], d[3 ] );
694
721
}
695
722
@@ -1456,6 +1483,17 @@ QImage* QgsWMSServer::getMap( HitTest* hitTest )
1456
1483
// theImage->save( QDir::tempPath() + QDir::separator() + "lastrender.png" );
1457
1484
// #endif
1458
1485
1486
+ thePainter.end ();
1487
+
1488
+ // test if width / height ratio of image is the same as the ratio of WIDTH / HEIGHT parameters. If not, the image has to be scaled (required by WMS spec)
1489
+ int widthParam = mParameters .value ( " WIDTH" , " 0" ).toInt ();
1490
+ int heightParam = mParameters .value ( " HEIGHT" , " 0" ).toInt ();
1491
+ if ( widthParam != theImage->width () || heightParam != theImage->height () )
1492
+ {
1493
+ // scale image
1494
+ *theImage = theImage->scaled ( widthParam, heightParam, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
1495
+ }
1496
+
1459
1497
return theImage;
1460
1498
}
1461
1499
@@ -1577,7 +1615,6 @@ int QgsWMSServer::getFeatureInfo( QDomDocument& result, const QString& version )
1577
1615
QgsRectangle mapExtent = mMapRenderer ->extent ();
1578
1616
double scaleDenominator = scaleCalc.calculate ( mapExtent, outputImage->width () );
1579
1617
mConfigParser ->setScaleDenominator ( scaleDenominator );
1580
- delete outputImage; // no longer needed for feature info
1581
1618
1582
1619
// read FEATURE_COUNT
1583
1620
int featureCount = 1 ;
@@ -1617,6 +1654,16 @@ int QgsWMSServer::getFeatureInfo( QDomDocument& result, const QString& version )
1617
1654
j = -1 ;
1618
1655
}
1619
1656
1657
+ // In case the output image is distorted (WIDTH/HEIGHT ratio not equal to BBOX width/height), I and J need to be adapted as well
1658
+ int widthParam = mParameters .value ( " WIDTH" , " -1" ).toInt ();
1659
+ int heightParam = mParameters .value ( " HEIGHT" , " -1" ).toInt ();
1660
+ if (( i != -1 && j != -1 && widthParam != -1 && heightParam != -1 ) && ( widthParam != outputImage->width () || heightParam != outputImage->height () ) )
1661
+ {
1662
+ i *= ( outputImage->width () / ( double )widthParam );
1663
+ j *= ( outputImage->height () / ( double )heightParam );
1664
+ }
1665
+ delete outputImage; // no longer needed for feature info
1666
+
1620
1667
// Normally, I/J or X/Y are mandatory parameters.
1621
1668
// However, in order to make attribute only queries via the FILTER parameter, it is allowed to skip them if the FILTER parameter is there
1622
1669
@@ -1953,6 +2000,29 @@ QImage* QgsWMSServer::createImage( int width, int height ) const
1953
2000
}
1954
2001
}
1955
2002
2003
+ // Adapt width / height if the aspect ratio does not correspond with the BBOX.
2004
+ // Required by WMS spec. 1.3.
2005
+ bool bboxOk;
2006
+ QgsRectangle mapExtent = _parseBBOX ( mParameters .value ( " BBOX" ), bboxOk );
2007
+ if ( bboxOk )
2008
+ {
2009
+ double mapWidthHeightRatio = mapExtent.width () / mapExtent.height ();
2010
+ double imageWidthHeightRatio = ( double )width / ( double )height;
2011
+ if ( !qgsDoubleNear ( mapWidthHeightRatio, imageWidthHeightRatio, 0.0001 ) )
2012
+ {
2013
+ if ( mapWidthHeightRatio >= imageWidthHeightRatio )
2014
+ {
2015
+ // decrease image height
2016
+ height = width / mapWidthHeightRatio;
2017
+ }
2018
+ else
2019
+ {
2020
+ // decrease image width
2021
+ width = height * mapWidthHeightRatio;
2022
+ }
2023
+ }
2024
+ }
2025
+
1956
2026
if ( width < 0 || height < 0 )
1957
2027
{
1958
2028
return nullptr ;
@@ -1969,6 +2039,19 @@ QImage* QgsWMSServer::createImage( int width, int height ) const
1969
2039
// transparent parameter
1970
2040
bool transparent = mParameters .value ( " TRANSPARENT" ).compare ( " true" , Qt::CaseInsensitive ) == 0 ;
1971
2041
2042
+ // background color
2043
+ QString bgColorString = mParameters .value ( " BGCOLOR" );
2044
+ if ( bgColorString.startsWith ( " 0x" , Qt::CaseInsensitive ) )
2045
+ {
2046
+ bgColorString.replace ( 0 , 2 , " #" );
2047
+ }
2048
+ QColor backgroundColor;
2049
+ backgroundColor.setNamedColor ( bgColorString );
2050
+ if ( !backgroundColor.isValid () )
2051
+ {
2052
+ backgroundColor = QColor ( Qt::white );
2053
+ }
2054
+
1972
2055
// use alpha channel only if necessary because it slows down performance
1973
2056
if ( transparent && !jpeg )
1974
2057
{
@@ -1978,7 +2061,7 @@ QImage* QgsWMSServer::createImage( int width, int height ) const
1978
2061
else
1979
2062
{
1980
2063
theImage = new QImage ( width, height, QImage::Format_RGB32 );
1981
- theImage->fill ( qRgb ( 255 , 255 , 255 ) );
2064
+ theImage->fill ( backgroundColor );
1982
2065
}
1983
2066
1984
2067
if ( !theImage )
@@ -2014,17 +2097,32 @@ int QgsWMSServer::configureMapRender( const QPaintDevice* paintDevice ) const
2014
2097
mMapRenderer ->setOutputSize ( QSize ( paintDevice->width (), paintDevice->height () ), paintDevice->logicalDpiX () );
2015
2098
2016
2099
// map extent
2017
- bool bboxOk;
2018
- QgsRectangle mapExtent = _parseBBOX ( mParameters .value ( " BBOX" , " 0,0,0,0" ), bboxOk );
2100
+ bool bboxOk = true ;
2101
+ QgsRectangle mapExtent;
2102
+ if ( mParameters .contains ( " BBOX" ) )
2103
+ {
2104
+ mapExtent = _parseBBOX ( mParameters .value ( " BBOX" , " 0,0,0,0" ), bboxOk );
2105
+ }
2106
+
2019
2107
if ( !bboxOk )
2020
2108
{
2021
2109
// throw a service exception
2022
2110
throw QgsMapServiceException ( " InvalidParameterValue" , " Invalid BBOX parameter" );
2023
2111
}
2024
2112
2113
+ if ( mParameters .contains ( " BBOX" ) && mapExtent.isEmpty () )
2114
+ {
2115
+ throw QgsMapServiceException ( " InvalidParameterValue" , " BBOX is empty" );
2116
+ }
2117
+
2025
2118
QGis::UnitType mapUnits = QGis::Degrees;
2026
2119
2027
2120
QString crs = mParameters .value ( " CRS" , mParameters .value ( " SRS" ) );
2121
+ if ( crs.compare ( " CRS:84" , Qt::CaseInsensitive ) == 0 )
2122
+ {
2123
+ crs = QString ( " EPSG:4326" );
2124
+ mapExtent.invert ();
2125
+ }
2028
2126
2029
2127
QgsCoordinateReferenceSystem outputCRS;
2030
2128
@@ -2151,6 +2249,12 @@ bool QgsWMSServer::infoPointToMapCoordinates( int i, int j, QgsPoint* infoPoint,
2151
2249
return false ;
2152
2250
}
2153
2251
2252
+ // check if i, j are in the pixel range of the image
2253
+ if ( i < 0 || i > mapRenderer->width () || j < 0 || j > mapRenderer->height () )
2254
+ {
2255
+ throw QgsMapServiceException ( " InvalidPoint" , " I/J parameters not within the pixel range" );
2256
+ }
2257
+
2154
2258
double xRes = mapRenderer->extent ().width () / mapRenderer->width ();
2155
2259
double yRes = mapRenderer->extent ().height () / mapRenderer->height ();
2156
2260
infoPoint->setX ( mapRenderer->extent ().xMinimum () + i * xRes + xRes / 2.0 );
0 commit comments