QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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
83  {
84  // lookup for png with mode
85  QRegularExpression modeExpr = QRegularExpression( QStringLiteral( "image/png\\s*;\\s*mode=([^;]+)" ),
86  QRegularExpression::CaseInsensitiveOption );
87 
88  QRegularExpressionMatch match = modeExpr.match( format );
89  QString mode = match.captured( 1 );
90  if ( mode.compare( QLatin1String( "16bit" ), Qt::CaseInsensitive ) == 0 )
91  return PNG16;
92  if ( mode.compare( QLatin1String( "8bit" ), Qt::CaseInsensitive ) == 0 )
93  return PNG8;
94  if ( mode.compare( QLatin1String( "1bit" ), Qt::CaseInsensitive ) == 0 )
95  return PNG1;
96  }
97 
98  return UNKN;
99  }
100 
101  // Write image response
102  void writeImage( QgsServerResponse &response, QImage &img, const QString &formatStr,
103  int imageQuality )
104  {
105  ImageOutputFormat outputFormat = parseImageFormat( formatStr );
106  QImage result;
107  QString saveFormat;
108  QString contentType;
109  switch ( outputFormat )
110  {
111  case PNG:
112  result = img;
113  contentType = "image/png";
114  saveFormat = "PNG";
115  break;
116  case PNG8:
117  {
118  QVector<QRgb> colorTable;
119 
120  // Rendering is made with the format QImage::Format_ARGB32_Premultiplied
121  // So we need to convert it in QImage::Format_ARGB32 in order to properly build
122  // the color table.
123  QImage img256 = img.convertToFormat( QImage::Format_ARGB32 );
124  medianCut( colorTable, 256, img256 );
125  result = img256.convertToFormat( QImage::Format_Indexed8, colorTable,
126  Qt::ColorOnly | Qt::ThresholdDither |
127  Qt::ThresholdAlphaDither | Qt::NoOpaqueDetection );
128  }
129  contentType = "image/png";
130  saveFormat = "PNG";
131  break;
132  case PNG16:
133  result = img.convertToFormat( QImage::Format_ARGB4444_Premultiplied );
134  contentType = "image/png";
135  saveFormat = "PNG";
136  break;
137  case PNG1:
138  result = img.convertToFormat( QImage::Format_Mono,
139  Qt::MonoOnly | Qt::ThresholdDither |
140  Qt::ThresholdAlphaDither | Qt::NoOpaqueDetection );
141  contentType = "image/png";
142  saveFormat = "PNG";
143  break;
144  case JPEG:
145  result = img;
146  contentType = "image/jpeg";
147  saveFormat = "JPEG";
148  break;
149  default:
150  QgsMessageLog::logMessage( QString( "Unsupported format string %1" ).arg( formatStr ) );
151  saveFormat = UNKN;
152  break;
153  }
154 
155  if ( outputFormat != UNKN )
156  {
157  response.setHeader( "Content-Type", contentType );
158  if ( saveFormat == "JPEG" )
159  {
160  result.save( response.io(), qPrintable( saveFormat ), imageQuality );
161  }
162  else
163  {
164  result.save( response.io(), qPrintable( saveFormat ) );
165  }
166  }
167  else
168  {
170  parameter.mValue = formatStr;
172  parameter );
173  }
174  }
175 } // namespace QgsWms
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...
SERVER_EXPORT QString wmsServiceUrl(const QgsProject &project)
Returns the WMS service url defined in a QGIS project.
Exception thrown in case of malformed request.
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...
void writeImage(QgsServerResponse &response, QImage &img, const QString &formatStr, int imageQuality)
Write image response.
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).
Encapsulates a QGIS project, including sets of map layers and their styles, layouts, annotations, canvases, etc.
Definition: qgsproject.h:89
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:32
ImageOutputFormat
Supported image output format.
Definition: qgswmsutils.h:39
QgsServerResponse Class defining response interface passed to services QgsService::executeRequest() m...
WMS parameter received from the client.
ImageOutputFormat parseImageFormat(const QString &format)
Parse image format parameter.
Definition: qgswmsutils.cpp:70