QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
Loading...
Searching...
No Matches
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 "qgswmsutils.h"
23
24#include "qgsmediancut.h"
25#include "qgsmodule.h"
26#include "qgsproject.h"
29
30#include <QRegularExpression>
31#include <QString>
32
33using namespace Qt::StringLiterals;
34
35namespace QgsWms
36{
38 {
39 return u"1.3.0"_s;
40 }
41
42 QUrl serviceUrl( const QgsServerRequest &request, const QgsProject *project, const QgsServerSettings &settings )
43 {
44 QUrl href;
45 href.setUrl( QgsServerProjectUtils::wmsServiceUrl( project ? *project : *QgsProject::instance(), request, settings ) );
46
47 // Build default url
48 if ( href.isEmpty() )
49 {
50 static const QSet<QString> sFilter { u"REQUEST"_s, u"VERSION"_s, u"SERVICE"_s, u"LAYERS"_s, u"STYLES"_s, u"SLD_VERSION"_s, u"_DC"_s };
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( "png"_L1, Qt::CaseInsensitive ) == 0 || format.compare( "image/png"_L1, Qt::CaseInsensitive ) == 0 )
72 {
74 }
75 else if ( format.compare( "jpg "_L1, Qt::CaseInsensitive ) == 0 || format.compare( "image/jpeg"_L1, Qt::CaseInsensitive ) == 0 )
76 {
78 }
79 else if ( format.compare( "webp"_L1, Qt::CaseInsensitive ) == 0 || format.compare( "image/webp"_L1, Qt::CaseInsensitive ) == 0 )
80 {
82 }
83 else
84 {
85 // lookup for png with mode
86 const thread_local QRegularExpression modeExpr = QRegularExpression( u"image/png\\s*;\\s*mode=([^;]+)"_s, QRegularExpression::CaseInsensitiveOption );
87
88 const QRegularExpressionMatch match = modeExpr.match( format );
89 const QString mode = match.captured( 1 );
90 if ( mode.compare( "16bit"_L1, Qt::CaseInsensitive ) == 0 )
92 if ( mode.compare( "8bit"_L1, Qt::CaseInsensitive ) == 0 )
94 if ( mode.compare( "1bit"_L1, Qt::CaseInsensitive ) == 0 )
96 }
97
99 }
100
101 // Write image response
102 void writeImage( QgsServerResponse &response, QImage &img, const QString &formatStr, int imageQuality )
103 {
104 const ImageOutputFormat outputFormat = parseImageFormat( formatStr );
105 QImage result;
106 QString saveFormat;
107 QString contentType;
108 switch ( outputFormat )
109 {
111 result = img;
112 contentType = u"image/png"_s;
113 saveFormat = u"PNG"_s;
114 break;
116 {
117 QVector<QRgb> colorTable;
118
119 // Rendering is made with the format QImage::Format_ARGB32_Premultiplied
120 // So we need to convert it in QImage::Format_ARGB32 in order to properly build
121 // the color table.
122 const QImage img256 = img.convertToFormat( QImage::Format_ARGB32 );
123 medianCut( colorTable, 256, img256 );
124 result = img256.convertToFormat( QImage::Format_Indexed8, colorTable, Qt::ColorOnly | Qt::ThresholdDither | Qt::ThresholdAlphaDither | Qt::NoOpaqueDetection );
125 }
126 contentType = u"image/png"_s;
127 saveFormat = u"PNG"_s;
128 break;
130 result = img.convertToFormat( QImage::Format_ARGB4444_Premultiplied );
131 contentType = u"image/png"_s;
132 saveFormat = u"PNG"_s;
133 break;
135 result = img.convertToFormat( QImage::Format_Mono, Qt::MonoOnly | Qt::ThresholdDither | Qt::ThresholdAlphaDither | Qt::NoOpaqueDetection );
136 contentType = u"image/png"_s;
137 saveFormat = u"PNG"_s;
138 break;
140 result = img;
141 contentType = u"image/jpeg"_s;
142 saveFormat = u"JPEG"_s;
143 break;
145 result = img;
146 contentType = u"image/webp"_s;
147 saveFormat = u"WEBP"_s;
148 break;
150 QgsMessageLog::logMessage( u"Unsupported format string %1"_s.arg( formatStr ) );
151 saveFormat = u"Unknown"_s;
152 break;
153 }
154
155 // Preserve DPI, some conversions, in particular the one for 8bit will drop this information
156 result.setDotsPerMeterX( img.dotsPerMeterX() );
157 result.setDotsPerMeterY( img.dotsPerMeterY() );
158
159 if ( outputFormat != ImageOutputFormat::Unknown )
160 {
161 response.setHeader( "Content-Type", contentType );
162 if ( saveFormat == "JPEG"_L1 || saveFormat == "WEBP"_L1 )
163 {
164 result.save( response.io(), qPrintable( saveFormat ), imageQuality );
165 }
166 else
167 {
168 result.save( response.io(), qPrintable( saveFormat ) );
169 }
170 }
171 else
172 {
174 parameter.mValue = formatStr;
176 }
177 }
178} // namespace QgsWms
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
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:113
static QgsProject * instance()
Returns the QgsProject singleton instance.
static QString wmsServiceUrl(const QgsProject &project, const QgsServerRequest &request=QgsServerRequest(), const QgsServerSettings &settings=QgsServerSettings())
Returns the WMS service url.
Defines requests passed to QgsService classes.
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...
Defines the response interface passed to QgsService.
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.
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.
QString implementationVersion()
Returns the highest version supported by this implementation.
ImageOutputFormat
Supported image output format.
Definition qgswmsutils.h:41
@ Unknown
Unknown/invalid format.
Definition qgswmsutils.h:42
ImageOutputFormat parseImageFormat(const QString &format)
Parse image format parameter.
QUrl serviceUrl(const QgsServerRequest &request, const QgsProject *project, const QgsServerSettings &settings)
Returns WMS service URL.