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