QGIS API Documentation  3.6.0-Noosa (5873452)
qgswmsutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgswmsutils.cpp
3  -------------------------
4  begin : December 20 , 2016
5  copyright : (C) 2007 by Marco Hugentobler ( parts from qgswmshandler)
6  (C) 2014 by Alessandro Pasotti ( parts from qgswmshandler)
7  (C) 2016 by David Marteau
8  email : marco dot hugentobler at karto dot baug dot ethz dot ch
9  a dot pasotti at itopen dot it
10  david dot marteau at 3liz dot com
11  ***************************************************************************/
12 
13 /***************************************************************************
14  * *
15  * This program is free software; you can redistribute it and/or modify *
16  * it under the terms of the GNU General Public License as published by *
17  * the Free Software Foundation; either version 2 of the License, or *
18  * (at your option) any later version. *
19  * *
20  ***************************************************************************/
21 
22 #include <QRegularExpression>
23 
24 #include "qgsmodule.h"
25 #include "qgswmsutils.h"
26 #include "qgsmediancut.h"
27 #include "qgsserverprojectutils.h"
28 #include "qgswmsserviceexception.h"
29 
30 namespace QgsWms
31 {
33  {
34  return QStringLiteral( "1.3.0" );
35  }
36 
37  QUrl serviceUrl( const QgsServerRequest &request, const QgsProject *project )
38  {
39  QUrl href;
40  if ( project )
41  {
42  href.setUrl( QgsServerProjectUtils::wmsServiceUrl( *project ) );
43  }
44 
45  // Build default url
46  if ( href.isEmpty() )
47  {
48  static QSet<QString> sFilter
49  {
50  QStringLiteral( "REQUEST" ),
51  QStringLiteral( "VERSION" ),
52  QStringLiteral( "SERVICE" ),
53  QStringLiteral( "LAYERS" ),
54  QStringLiteral( "STYLES" ),
55  QStringLiteral( "SLD_VERSION" ),
56  QStringLiteral( "_DC" )
57  };
58 
59  href = request.originalUrl();
60  QUrlQuery q( href );
61 
62  for ( auto param : q.queryItems() )
63  {
64  if ( sFilter.contains( param.first.toUpper() ) )
65  q.removeAllQueryItems( param.first );
66  }
67 
68  href.setQuery( q );
69  }
70 
71  return href;
72  }
73 
74 
75  ImageOutputFormat parseImageFormat( const QString &format )
76  {
77  if ( format.compare( QLatin1String( "png" ), Qt::CaseInsensitive ) == 0 ||
78  format.compare( QLatin1String( "image/png" ), Qt::CaseInsensitive ) == 0 )
79  {
80  return PNG;
81  }
82  else if ( format.compare( QLatin1String( "jpg " ), Qt::CaseInsensitive ) == 0 ||
83  format.compare( QLatin1String( "image/jpeg" ), Qt::CaseInsensitive ) == 0 )
84  {
85  return JPEG;
86  }
87  else
88  {
89  // lookup for png with mode
90  QRegularExpression modeExpr = QRegularExpression( QStringLiteral( "image/png\\s*;\\s*mode=([^;]+)" ),
91  QRegularExpression::CaseInsensitiveOption );
92 
93  QRegularExpressionMatch match = modeExpr.match( format );
94  QString mode = match.captured( 1 );
95  if ( mode.compare( QLatin1String( "16bit" ), Qt::CaseInsensitive ) == 0 )
96  return PNG16;
97  if ( mode.compare( QLatin1String( "8bit" ), Qt::CaseInsensitive ) == 0 )
98  return PNG8;
99  if ( mode.compare( QLatin1String( "1bit" ), Qt::CaseInsensitive ) == 0 )
100  return PNG1;
101  }
102 
103  return UNKN;
104  }
105 
106  void readLayersAndStyles( const QgsServerRequest::Parameters &parameters, QStringList &layersList, QStringList &stylesList )
107  {
108  //get layer and style lists from the parameters trying LAYERS and LAYER as well as STYLE and STYLES for GetLegendGraphic compatibility
109  layersList = parameters.value( QStringLiteral( "LAYER" ) ).split( ',', QString::SkipEmptyParts );
110  layersList = layersList + parameters.value( QStringLiteral( "LAYERS" ) ).split( ',', QString::SkipEmptyParts );
111  stylesList = parameters.value( QStringLiteral( "STYLE" ) ).split( ',', QString::SkipEmptyParts );
112  stylesList = stylesList + parameters.value( QStringLiteral( "STYLES" ) ).split( ',', QString::SkipEmptyParts );
113  }
114 
115 
116  // Write image response
117  void writeImage( QgsServerResponse &response, QImage &img, const QString &formatStr,
118  int imageQuality )
119  {
120  ImageOutputFormat outputFormat = parseImageFormat( formatStr );
121  QImage result;
122  QString saveFormat;
123  QString contentType;
124  switch ( outputFormat )
125  {
126  case PNG:
127  result = img;
128  contentType = "image/png";
129  saveFormat = "PNG";
130  break;
131  case PNG8:
132  {
133  QVector<QRgb> colorTable;
134  medianCut( colorTable, 256, img );
135  result = img.convertToFormat( QImage::Format_Indexed8, colorTable,
136  Qt::ColorOnly | Qt::ThresholdDither |
137  Qt::ThresholdAlphaDither | Qt::NoOpaqueDetection );
138  }
139  contentType = "image/png";
140  saveFormat = "PNG";
141  break;
142  case PNG16:
143  result = img.convertToFormat( QImage::Format_ARGB4444_Premultiplied );
144  contentType = "image/png";
145  saveFormat = "PNG";
146  break;
147  case PNG1:
148  result = img.convertToFormat( QImage::Format_Mono,
149  Qt::MonoOnly | Qt::ThresholdDither |
150  Qt::ThresholdAlphaDither | Qt::NoOpaqueDetection );
151  contentType = "image/png";
152  saveFormat = "PNG";
153  break;
154  case JPEG:
155  result = img;
156  contentType = "image/jpeg";
157  saveFormat = "JPEG";
158  break;
159  default:
160  QgsMessageLog::logMessage( QString( "Unsupported format string %1" ).arg( formatStr ) );
161  saveFormat = UNKN;
162  break;
163  }
164 
165  if ( outputFormat != UNKN )
166  {
167  response.setHeader( "Content-Type", contentType );
168  if ( saveFormat == "JPEG" )
169  {
170  result.save( response.io(), qPrintable( saveFormat ), imageQuality );
171  }
172  else
173  {
174  result.save( response.io(), qPrintable( saveFormat ) );
175  }
176  }
177  else
178  {
179  throw QgsServiceException( "InvalidFormat",
180  QString( "Output format '%1' is not supported in the GetMap request" ).arg( formatStr ) );
181  }
182  }
183 
184  QgsRectangle parseBbox( const QString &bboxStr )
185  {
186  QStringList lst = bboxStr.split( ',' );
187  if ( lst.count() != 4 )
188  return QgsRectangle();
189 
190  double d[4];
191  bool ok;
192  for ( int i = 0; i < 4; i++ )
193  {
194  lst[i].replace( ' ', '+' );
195  d[i] = lst[i].toDouble( &ok );
196  if ( !ok )
197  return QgsRectangle();
198  }
199  return QgsRectangle( d[0], d[1], d[2], d[3] );
200  }
201 
202 } // namespace QgsWms
203 
204 
virtual void setHeader(const QString &key, const QString &value)=0
Set Header entry Add Header entry to the response Note that it is usually an error to set Header afte...
A rectangle specified with double values.
Definition: qgsrectangle.h:41
SERVER_EXPORT QString wmsServiceUrl(const QgsProject &project)
Returns the WMS service url defined in a QGIS project.
QUrl originalUrl() const
Returns the request url as seen by the web server, by default this is equal to the url seen by QGIS s...
Exception class for WMS service exceptions.
void writeImage(QgsServerResponse &response, QImage &img, const QString &formatStr, int imageQuality)
Write image response.
QgsRectangle parseBbox(const QString &bboxStr)
Parse bbox parameter.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
QString ImplementationVersion()
Returns the highest version supported by this implementation.
Definition: qgswmsutils.cpp:32
Reads and writes project states.
Definition: qgsproject.h:89
void readLayersAndStyles(const QgsServerRequest::Parameters &parameters, QStringList &layersList, QStringList &stylesList)
Reads the layers and style lists from the parameters LAYERS and STYLES.
Median cut implementation.
void medianCut(QVector< QRgb > &colorTable, int nColors, const QImage &inputImage)
Median cut implementation used when reducing RGB colors to palletized colors.
QgsServerRequest Class defining request interface passed to services QgsService::executeRequest() met...
virtual QIODevice * io()=0
Returns the underlying QIODevice.
QUrl serviceUrl(const QgsServerRequest &request, const QgsProject *project)
Returns WMS service URL.
Definition: qgswmsutils.cpp:37
ImageOutputFormat
Supported image output format.
Definition: qgswmsutils.h:39
QgsServerResponse Class defining response interface passed to services QgsService::executeRequest() m...
ImageOutputFormat parseImageFormat(const QString &format)
Parse image format parameter.
Definition: qgswmsutils.cpp:75
QMap< QString, QString > Parameters