QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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 "qgsconfigcache.h"
28 #include "qgsserverprojectutils.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 
135  // Rendering is made with the format QImage::Format_ARGB32_Premultiplied
136  // So we need to convert it in QImage::Format_ARGB32 in order to properly build
137  // the color table.
138  QImage img256 = img.convertToFormat( QImage::Format_ARGB32 );
139  medianCut( colorTable, 256, img256 );
140  result = img256.convertToFormat( QImage::Format_Indexed8, colorTable,
141  Qt::ColorOnly | Qt::ThresholdDither |
142  Qt::ThresholdAlphaDither | Qt::NoOpaqueDetection );
143  }
144  contentType = "image/png";
145  saveFormat = "PNG";
146  break;
147  case PNG16:
148  result = img.convertToFormat( QImage::Format_ARGB4444_Premultiplied );
149  contentType = "image/png";
150  saveFormat = "PNG";
151  break;
152  case PNG1:
153  result = img.convertToFormat( QImage::Format_Mono,
154  Qt::MonoOnly | Qt::ThresholdDither |
155  Qt::ThresholdAlphaDither | Qt::NoOpaqueDetection );
156  contentType = "image/png";
157  saveFormat = "PNG";
158  break;
159  case JPEG:
160  result = img;
161  contentType = "image/jpeg";
162  saveFormat = "JPEG";
163  break;
164  default:
165  QgsMessageLog::logMessage( QString( "Unsupported format string %1" ).arg( formatStr ) );
166  saveFormat = UNKN;
167  break;
168  }
169 
170  if ( outputFormat != UNKN )
171  {
172  response.setHeader( "Content-Type", contentType );
173  if ( saveFormat == "JPEG" )
174  {
175  result.save( response.io(), qPrintable( saveFormat ), imageQuality );
176  }
177  else
178  {
179  result.save( response.io(), qPrintable( saveFormat ) );
180  }
181  }
182  else
183  {
184  throw QgsServiceException( "InvalidFormat",
185  QString( "Output format '%1' is not supported in the GetMap request" ).arg( formatStr ) );
186  }
187  }
188 
189  QgsRectangle parseBbox( const QString &bboxStr )
190  {
191  QStringList lst = bboxStr.split( ',' );
192  if ( lst.count() != 4 )
193  return QgsRectangle();
194 
195  double d[4];
196  bool ok;
197  for ( int i = 0; i < 4; i++ )
198  {
199  lst[i].replace( ' ', '+' );
200  d[i] = lst[i].toDouble( &ok );
201  if ( !ok )
202  return QgsRectangle();
203  }
204  return QgsRectangle( d[0], d[1], d[2], d[3] );
205  }
206 
207 } // namespace QgsWms
208 
209 
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:40
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:40
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