Skip to content

Commit

Permalink
Support hidpi sprites when converting mapboxgl styles
Browse files Browse the repository at this point in the history
  • Loading branch information
nirvn authored and nyalldawson committed Sep 14, 2020
1 parent 1312cfe commit 1de8d01
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 47 deletions.
Expand Up @@ -495,7 +495,7 @@ Converts a MapBox GL expression to a QGIS expression.
This is private API only, and may change in future QGIS versions
%End

static QImage retrieveSprite( const QString &name, QgsMapBoxGlStyleConversionContext &context );
static QImage retrieveSprite( const QString &name, QgsMapBoxGlStyleConversionContext &context, QSize &spriteSize );
%Docstring
Retrieves the sprite image with the specified ``name``, taken from the specified ``context``.

Expand Down
33 changes: 15 additions & 18 deletions src/core/vectortile/qgsmapboxglstyleconverter.cpp
Expand Up @@ -2186,7 +2186,7 @@ QString QgsMapBoxGlStyleConverter::parseExpression( const QVariantList &expressi
}
}

QImage QgsMapBoxGlStyleConverter::retrieveSprite( const QString &name, QgsMapBoxGlStyleConversionContext &context )
QImage QgsMapBoxGlStyleConverter::retrieveSprite( const QString &name, QgsMapBoxGlStyleConversionContext &context, QSize &spriteSize )
{
if ( context.spriteImage().isNull() )
{
Expand All @@ -2211,18 +2211,19 @@ QImage QgsMapBoxGlStyleConverter::retrieveSprite( const QString &name, QgsMapBox
return QImage();
}

spriteSize = sprite.size() / spriteDefinition.value( QStringLiteral( "pixelRatio" ) ).toDouble() * context.pixelSizeConversionFactor();
return sprite;
}

QString QgsMapBoxGlStyleConverter::retrieveSpriteAsBase64( const QVariant &value, QgsMapBoxGlStyleConversionContext &context, QSize &spriteSize, QString &spriteProperty, QString &spriteSizeProperty )
{
QString spritePath;

auto prepareSprite = [context]( const QImage & sprite, QString & path, QSize & size )
auto prepareBase64 = []( const QImage & sprite )
{
QString path;
if ( !sprite.isNull() )
{
size = sprite.size() * context.pixelSizeConversionFactor();
QByteArray blob;
QBuffer buffer( &blob );
buffer.open( QIODevice::WriteOnly );
Expand All @@ -2232,11 +2233,7 @@ QString QgsMapBoxGlStyleConverter::retrieveSpriteAsBase64( const QVariant &value
path = QString( encoded );
path.prepend( QLatin1String( "base64:" ) );
}
else
{
path.clear();
size = QSize();
}
return path;
};

switch ( value.type() )
Expand Down Expand Up @@ -2265,8 +2262,8 @@ QString QgsMapBoxGlStyleConverter::retrieveSpriteAsBase64( const QVariant &value
QSize size;
QString path;
const QString fieldValue = match.captured( 1 );
const QImage sprite = retrieveSprite( name, context );
prepareSprite( sprite, path, size );
const QImage sprite = retrieveSprite( name, context, size );
path = prepareBase64( sprite );
if ( spritePath.isEmpty() && !path.isEmpty() )
{
spritePath = path;
Expand All @@ -2287,8 +2284,8 @@ QString QgsMapBoxGlStyleConverter::retrieveSpriteAsBase64( const QVariant &value
{
spriteProperty.clear();
spriteSizeProperty.clear();
const QImage sprite = retrieveSprite( spriteName, context );
prepareSprite( sprite, spritePath, spriteSize );
const QImage sprite = retrieveSprite( spriteName, context, spriteSize );
spritePath = prepareBase64( sprite );
}
break;
}
Expand All @@ -2303,8 +2300,8 @@ QString QgsMapBoxGlStyleConverter::retrieveSpriteAsBase64( const QVariant &value
QSize size;
QImage sprite;

sprite = retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context );
prepareSprite( sprite, spritePath, spriteSize );
sprite = retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context, spriteSize );
spritePath = prepareBase64( sprite );

spriteProperty = QStringLiteral( "CASE WHEN @zoom_level < %1 THEN '%2'" )
.arg( stops.value( 0 ).toList().value( 0 ).toString() )
Expand All @@ -2316,8 +2313,8 @@ QString QgsMapBoxGlStyleConverter::retrieveSpriteAsBase64( const QVariant &value
for ( int i = 0; i < stops.size() - 1; ++i )
{
;
sprite = retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context );
prepareSprite( sprite, path, size );
sprite = retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context, size );
path = prepareBase64( sprite );

spriteProperty += QStringLiteral( " WHEN @zoom_level >= %1 AND @zoom_level < %2 "
"THEN '%3'" )
Expand All @@ -2330,8 +2327,8 @@ QString QgsMapBoxGlStyleConverter::retrieveSpriteAsBase64( const QVariant &value
stops.value( i + 1 ).toList().value( 0 ).toString() )
.arg( size.width() );
}
sprite = retrieveSprite( stops.last().toList().value( 1 ).toString(), context );
prepareSprite( sprite, path, size );
sprite = retrieveSprite( stops.last().toList().value( 1 ).toString(), context, size );
path = prepareBase64( sprite );

spriteProperty += QStringLiteral( " WHEN @zoom_level >= %1 "
"THEN '%2' END" )
Expand Down
2 changes: 1 addition & 1 deletion src/core/vectortile/qgsmapboxglstyleconverter.h
Expand Up @@ -482,7 +482,7 @@ class CORE_EXPORT QgsMapBoxGlStyleConverter
* The \a context must have valid sprite definitions and images set via QgsMapBoxGlStyleConversionContext::setSprites()
* prior to conversion.
*/
static QImage retrieveSprite( const QString &name, QgsMapBoxGlStyleConversionContext &context );
static QImage retrieveSprite( const QString &name, QgsMapBoxGlStyleConversionContext &context, QSize &spriteSize );

/**
* Retrieves the sprite image with the specified \a name, taken from the specified \a context as a base64 encoded value
Expand Down
59 changes: 32 additions & 27 deletions src/core/vectortile/qgsvectortilelayer.cpp
Expand Up @@ -351,46 +351,51 @@ QString QgsVectorTileLayer::loadDefaultStyle( bool &resultFlag )
{
spriteUriBase = styleUrl + '/' + styleDefinition.value( QStringLiteral( "sprite" ) ).toString();
}
QNetworkRequest request = QNetworkRequest( QUrl( spriteUriBase + QStringLiteral( ".json" ) ) );

QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsVectorTileLayer" ) );

QgsBlockingNetworkRequest networkRequest;
switch ( networkRequest.get( request ) )
for ( int resolution = 2; resolution > 0; resolution-- )
{
case QgsBlockingNetworkRequest::NoError:
QNetworkRequest request = QNetworkRequest( QUrl( spriteUriBase + QStringLiteral( "%1.json" ).arg( resolution > 1 ? QStringLiteral( "@%1x" ).arg( resolution ) : QString() ) ) );
QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsVectorTileLayer" ) );
QgsBlockingNetworkRequest networkRequest;
switch ( networkRequest.get( request ) )
{
const QgsNetworkReplyContent content = networkRequest.reply();
const QVariantMap spriteDefinition = QgsJsonUtils::parseJson( content.content() ).toMap();
case QgsBlockingNetworkRequest::NoError:
{
const QgsNetworkReplyContent content = networkRequest.reply();
const QVariantMap spriteDefinition = QgsJsonUtils::parseJson( content.content() ).toMap();

// retrieve sprite images
QNetworkRequest request = QNetworkRequest( QUrl( spriteUriBase + QStringLiteral( ".png" ) ) );
// retrieve sprite images
QNetworkRequest request = QNetworkRequest( QUrl( spriteUriBase + QStringLiteral( "%1.png" ).arg( resolution > 1 ? QStringLiteral( "@%1x" ).arg( resolution ) : QString() ) ) );

QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsVectorTileLayer" ) );
QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsVectorTileLayer" ) );

QgsBlockingNetworkRequest networkRequest;
switch ( networkRequest.get( request ) )
{
case QgsBlockingNetworkRequest::NoError:
QgsBlockingNetworkRequest networkRequest;
switch ( networkRequest.get( request ) )
{
const QgsNetworkReplyContent imageContent = networkRequest.reply();
QImage spriteImage( QImage::fromData( imageContent.content() ) );
context.setSprites( spriteImage, spriteDefinition );
break;
case QgsBlockingNetworkRequest::NoError:
{
const QgsNetworkReplyContent imageContent = networkRequest.reply();
QImage spriteImage( QImage::fromData( imageContent.content() ) );
context.setSprites( spriteImage, spriteDefinition );
break;
}

case QgsBlockingNetworkRequest::NetworkError:
case QgsBlockingNetworkRequest::TimeoutError:
case QgsBlockingNetworkRequest::ServerExceptionError:
break;
}

case QgsBlockingNetworkRequest::NetworkError:
case QgsBlockingNetworkRequest::TimeoutError:
case QgsBlockingNetworkRequest::ServerExceptionError:
break;
break;
}

break;
case QgsBlockingNetworkRequest::NetworkError:
case QgsBlockingNetworkRequest::TimeoutError:
case QgsBlockingNetworkRequest::ServerExceptionError:
break;
}

case QgsBlockingNetworkRequest::NetworkError:
case QgsBlockingNetworkRequest::TimeoutError:
case QgsBlockingNetworkRequest::ServerExceptionError:
if ( !context.spriteDefinitions().isEmpty() )
break;
}
}
Expand Down

0 comments on commit 1de8d01

Please sign in to comment.