QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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 {
32  QUrl serviceUrl( const QgsServerRequest &request, const QgsProject *project )
33  {
34  QUrl href;
35  if ( project )
36  {
37  href.setUrl( QgsServerProjectUtils::wmsServiceUrl( *project ) );
38  }
39 
40  // Build default url
41  if ( href.isEmpty() )
42  {
43  static QSet<QString> sFilter
44  {
45  QStringLiteral( "REQUEST" ),
46  QStringLiteral( "VERSION" ),
47  QStringLiteral( "SERVICE" ),
48  QStringLiteral( "LAYERS" ),
49  QStringLiteral( "STYLES" ),
50  QStringLiteral( "SLD_VERSION" ),
51  QStringLiteral( "_DC" )
52  };
53 
54  href = request.originalUrl();
55  QUrlQuery q( href );
56 
57  for ( auto param : q.queryItems() )
58  {
59  if ( sFilter.contains( param.first.toUpper() ) )
60  q.removeAllQueryItems( param.first );
61  }
62 
63  href.setQuery( q );
64  }
65 
66  return href;
67  }
68 
69 
70  ImageOutputFormat parseImageFormat( const QString &format )
71  {
72  if ( format.compare( QLatin1String( "png" ), Qt::CaseInsensitive ) == 0 ||
73  format.compare( QLatin1String( "image/png" ), Qt::CaseInsensitive ) == 0 )
74  {
75  return PNG;
76  }
77  else if ( format.compare( QLatin1String( "jpg " ), Qt::CaseInsensitive ) == 0 ||
78  format.compare( QLatin1String( "image/jpeg" ), Qt::CaseInsensitive ) == 0 )
79  {
80  return JPEG;
81  }
82  else if ( format.compare( QLatin1String( "webp" ), Qt::CaseInsensitive ) == 0 ||
83  format.compare( QLatin1String( "image/webp" ), Qt::CaseInsensitive ) == 0 )
84  {
85  return WEBP;
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  // Write image response
107  void writeImage( QgsServerResponse &response, QImage &img, const QString &formatStr,
108  int imageQuality )
109  {
110  ImageOutputFormat outputFormat = parseImageFormat( formatStr );
111  QImage result;
112  QString saveFormat;
113  QString contentType;
114  switch ( outputFormat )
115  {
116  case PNG:
117  result = img;
118  contentType = "image/png";
119  saveFormat = "PNG";
120  break;
121  case PNG8:
122  {
123  QVector<QRgb> colorTable;
124 
125  // Rendering is made with the format QImage::Format_ARGB32_Premultiplied
126  // So we need to convert it in QImage::Format_ARGB32 in order to properly build
127  // the color table.
128  QImage img256 = img.convertToFormat( QImage::Format_ARGB32 );
129  medianCut( colorTable, 256, img256 );
130  result = img256.convertToFormat( QImage::Format_Indexed8, colorTable,
131  Qt::ColorOnly | Qt::ThresholdDither |
132  Qt::ThresholdAlphaDither | Qt::NoOpaqueDetection );
133  }
134  contentType = "image/png";
135  saveFormat = "PNG";
136  break;
137  case PNG16:
138  result = img.convertToFormat( QImage::Format_ARGB4444_Premultiplied );
139  contentType = "image/png";
140  saveFormat = "PNG";
141  break;
142  case PNG1:
143  result = img.convertToFormat( QImage::Format_Mono,
144  Qt::MonoOnly | Qt::ThresholdDither |
145  Qt::ThresholdAlphaDither | Qt::NoOpaqueDetection );
146  contentType = "image/png";
147  saveFormat = "PNG";
148  break;
149  case JPEG:
150  result = img;
151  contentType = "image/jpeg";
152  saveFormat = "JPEG";
153  break;
154  case WEBP:
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
QgsWms::parseImageFormat
ImageOutputFormat parseImageFormat(const QString &format)
Parse image format parameter.
Definition: qgswmsutils.cpp:70
QgsWms::UNKN
@ UNKN
Definition: qgswmsutils.h:41
QgsWms::WEBP
@ WEBP
Definition: qgswmsutils.h:47
qgswmsutils.h
qgsserverprojectutils.h
QgsWms::writeImage
void writeImage(QgsServerResponse &response, QImage &img, const QString &formatStr, int imageQuality)
Write image response.
Definition: qgswmsutils.cpp:107
QgsServerRequest
QgsServerRequest Class defining request interface passed to services QgsService::executeRequest() met...
Definition: qgsserverrequest.h:39
QgsServerProjectUtils::wmsServiceUrl
SERVER_EXPORT QString wmsServiceUrl(const QgsProject &project)
Returns the WMS service url defined in a QGIS project.
Definition: qgsserverprojectutils.cpp:301
QgsWms::QgsServiceException::OGC_InvalidFormat
@ OGC_InvalidFormat
Definition: qgswmsserviceexception.h:49
QgsWms::JPEG
@ JPEG
Definition: qgswmsutils.h:46
QgsProject
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:95
QgsWms::PNG8
@ PNG8
Definition: qgswmsutils.h:43
QgsWms::PNG16
@ PNG16
Definition: qgswmsutils.h:44
QgsWms::PNG
@ PNG
Definition: qgswmsutils.h:42
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:256
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:70
QgsWms
Median cut implementation.
Definition: qgsdxfwriter.cpp:23
QgsServerParameterDefinition::mValue
QVariant mValue
Definition: qgsserverparameters.h:165
QgsWms::QgsBadRequestException
Exception thrown in case of malformed request.
Definition: qgswmsserviceexception.h:214
QgsWms::serviceUrl
QUrl serviceUrl(const QgsServerRequest &request, const QgsProject *project)
Returns WMS service URL.
Definition: qgswmsutils.cpp:32
QgsWms::PNG1
@ PNG1
Definition: qgswmsutils.h:45
QgsMessageLog::logMessage
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).
Definition: qgsmessagelog.cpp:27
QgsWms::QgsWmsParameter::FORMAT
@ FORMAT
Definition: qgswmsparameters.h:146
QgsServerResponse::io
virtual QIODevice * io()=0
Returns the underlying QIODevice.
QgsWms::QgsWmsParameter
WMS parameter received from the client.
Definition: qgswmsparameters.h:99
qgsmodule.h
qgsmediancut.h
qgswmsserviceexception.h
QgsServerResponse
QgsServerResponse Class defining response interface passed to services QgsService::executeRequest() m...
Definition: qgsserverresponse.h:44
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...