QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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 #include "qgsproject.h"
30 
31 namespace QgsWms
32 {
33  QUrl serviceUrl( const QgsServerRequest &request, const QgsProject *project, const QgsServerSettings &settings )
34  {
35  QUrl href;
36  href.setUrl( QgsServerProjectUtils::wmsServiceUrl( project ? *project : *QgsProject::instance(), request, settings ) );
37 
38  // Build default url
39  if ( href.isEmpty() )
40  {
41  static const QSet<QString> sFilter
42  {
43  QStringLiteral( "REQUEST" ),
44  QStringLiteral( "VERSION" ),
45  QStringLiteral( "SERVICE" ),
46  QStringLiteral( "LAYERS" ),
47  QStringLiteral( "STYLES" ),
48  QStringLiteral( "SLD_VERSION" ),
49  QStringLiteral( "_DC" )
50  };
51 
52  href = request.originalUrl();
53  QUrlQuery q( href );
54 
55  const QList<QPair<QString, QString> > queryItems = q.queryItems();
56  for ( const QPair<QString, QString> &param : queryItems )
57  {
58  if ( sFilter.contains( param.first.toUpper() ) )
59  q.removeAllQueryItems( param.first );
60  }
61 
62  href.setQuery( q );
63  }
64 
65  return href;
66  }
67 
68 
69  ImageOutputFormat parseImageFormat( const QString &format )
70  {
71  if ( format.compare( QLatin1String( "png" ), Qt::CaseInsensitive ) == 0 ||
72  format.compare( QLatin1String( "image/png" ), Qt::CaseInsensitive ) == 0 )
73  {
74  return PNG;
75  }
76  else if ( format.compare( QLatin1String( "jpg " ), Qt::CaseInsensitive ) == 0 ||
77  format.compare( QLatin1String( "image/jpeg" ), Qt::CaseInsensitive ) == 0 )
78  {
79  return JPEG;
80  }
81  else if ( format.compare( QLatin1String( "webp" ), Qt::CaseInsensitive ) == 0 ||
82  format.compare( QLatin1String( "image/webp" ), Qt::CaseInsensitive ) == 0 )
83  {
84  return WEBP;
85  }
86  else
87  {
88  // lookup for png with mode
89  const QRegularExpression modeExpr = QRegularExpression( QStringLiteral( "image/png\\s*;\\s*mode=([^;]+)" ),
90  QRegularExpression::CaseInsensitiveOption );
91 
92  const QRegularExpressionMatch match = modeExpr.match( format );
93  const QString mode = match.captured( 1 );
94  if ( mode.compare( QLatin1String( "16bit" ), Qt::CaseInsensitive ) == 0 )
95  return PNG16;
96  if ( mode.compare( QLatin1String( "8bit" ), Qt::CaseInsensitive ) == 0 )
97  return PNG8;
98  if ( mode.compare( QLatin1String( "1bit" ), Qt::CaseInsensitive ) == 0 )
99  return PNG1;
100  }
101 
102  return UNKN;
103  }
104 
105  // Write image response
106  void writeImage( QgsServerResponse &response, QImage &img, const QString &formatStr,
107  int imageQuality )
108  {
109  const ImageOutputFormat outputFormat = parseImageFormat( formatStr );
110  QImage result;
111  QString saveFormat;
112  QString contentType;
113  switch ( outputFormat )
114  {
115  case PNG:
116  result = img;
117  contentType = "image/png";
118  saveFormat = "PNG";
119  break;
120  case PNG8:
121  {
122  QVector<QRgb> colorTable;
123 
124  // Rendering is made with the format QImage::Format_ARGB32_Premultiplied
125  // So we need to convert it in QImage::Format_ARGB32 in order to properly build
126  // the color table.
127  const QImage img256 = img.convertToFormat( QImage::Format_ARGB32 );
128  medianCut( colorTable, 256, img256 );
129  result = img256.convertToFormat( QImage::Format_Indexed8, colorTable,
130  Qt::ColorOnly | Qt::ThresholdDither |
131  Qt::ThresholdAlphaDither | Qt::NoOpaqueDetection );
132  }
133  contentType = "image/png";
134  saveFormat = "PNG";
135  break;
136  case PNG16:
137  result = img.convertToFormat( QImage::Format_ARGB4444_Premultiplied );
138  contentType = "image/png";
139  saveFormat = "PNG";
140  break;
141  case PNG1:
142  result = img.convertToFormat( QImage::Format_Mono,
143  Qt::MonoOnly | Qt::ThresholdDither |
144  Qt::ThresholdAlphaDither | Qt::NoOpaqueDetection );
145  contentType = "image/png";
146  saveFormat = "PNG";
147  break;
148  case JPEG:
149  result = img;
150  contentType = "image/jpeg";
151  saveFormat = "JPEG";
152  break;
153  case WEBP:
154  result = img;
155  contentType = QStringLiteral( "image/webp" );
156  saveFormat = QStringLiteral( "WEBP" );
157  break;
158  default:
159  QgsMessageLog::logMessage( QString( "Unsupported format string %1" ).arg( formatStr ) );
160  saveFormat = UNKN;
161  break;
162  }
163 
164  // Preserve DPI, some conversions, in particular the one for 8bit will drop this information
165  result.setDotsPerMeterX( img.dotsPerMeterX() );
166  result.setDotsPerMeterY( img.dotsPerMeterY() );
167 
168  if ( outputFormat != UNKN )
169  {
170  response.setHeader( "Content-Type", contentType );
171  if ( saveFormat == QLatin1String( "JPEG" ) || saveFormat == QLatin1String( "WEBP" ) )
172  {
173  result.save( response.io(), qPrintable( saveFormat ), imageQuality );
174  }
175  else
176  {
177  result.save( response.io(), qPrintable( saveFormat ) );
178  }
179  }
180  else
181  {
183  parameter.mValue = formatStr;
185  parameter );
186  }
187  }
188 } // namespace QgsWms
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:101
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:470
QgsServerRequest Class defining request interface passed to services QgsService::executeRequest() met...
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...
QgsServerResponse Class defining response interface passed to services QgsService::executeRequest() m...
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...
virtual QIODevice * io()=0
Returns the underlying QIODevice.
Provides a way to retrieve settings by prioritizing according to environment variables,...
Exception thrown in case of malformed request.
WMS parameter received from the client.
SERVER_EXPORT QString wmsServiceUrl(const QgsProject &project, const QgsServerRequest &request=QgsServerRequest(), const QgsServerSettings &settings=QgsServerSettings())
Returns the WMS service url.
Median cut implementation.
void writeImage(QgsServerResponse &response, QImage &img, const QString &formatStr, int imageQuality)
Write image response.
void medianCut(QVector< QRgb > &colorTable, int nColors, const QImage &inputImage)
Median cut implementation used when reducing RGB colors to palletized colors.
ImageOutputFormat
Supported image output format.
Definition: qgswmsutils.h:41
ImageOutputFormat parseImageFormat(const QString &format)
Parse image format parameter.
Definition: qgswmsutils.cpp:69
QUrl serviceUrl(const QgsServerRequest &request, const QgsProject *project, const QgsServerSettings &settings)
Returns WMS service URL.
Definition: qgswmsutils.cpp:33