Skip to content

Commit

Permalink
[arcgisrest] Fix drawing of large areas for non-tiled raster layers
Browse files Browse the repository at this point in the history
  • Loading branch information
nirvn committed Jun 8, 2019
1 parent 1c9586a commit 192c456
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 47 deletions.
121 changes: 74 additions & 47 deletions src/providers/arcgisrest/qgsamsprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,11 @@ QgsAmsProvider::QgsAmsProvider( const QString &uri, const ProviderOptions &optio

mTiled = mServiceInfo.value( QStringLiteral( "singleFusedMapCache" ) ).toBool() && mCrs.mapUnits() == QgsUnitTypes::DistanceMeters;

if ( mServiceInfo.contains( QStringLiteral( "maxImageWidth" ) ) )
mMaxImageWidth = mServiceInfo.value( QStringLiteral( "maxImageWidth" ) ).toInt();
if ( mServiceInfo.contains( QStringLiteral( "maxImageHeight" ) ) )
mMaxImageHeight = mServiceInfo.value( QStringLiteral( "maxImageHeight" ) ).toInt();

const QVariantList subLayersList = mLayerInfo.value( QStringLiteral( "subLayers" ) ).toList();
mSubLayers.reserve( subLayersList.size() );
for ( const QVariant &sublayer : subLayersList )
Expand Down Expand Up @@ -276,6 +281,8 @@ QgsAmsProvider::QgsAmsProvider( const QgsAmsProvider &other, const QgsDataProvid
, mRequestHeaders( other.mRequestHeaders )
, mTiled( other.mTiled )
, mImageServer( other.mImageServer )
, mMaxImageWidth( other.mMaxImageWidth )
, mMaxImageHeight( other.mMaxImageHeight )
, mLayerMetadata( other.mLayerMetadata )
, mResolutions( other.mResolutions )
// intentionally omitted:
Expand Down Expand Up @@ -657,60 +664,80 @@ QImage QgsAmsProvider::draw( const QgsRectangle &viewExtent, int pixelWidth, int
return mCachedImage;
}

QUrl requestUrl( dataSource.param( QStringLiteral( "url" ) ) + ( mImageServer ? "/exportImage" : "/export" ) );
requestUrl.addQueryItem( QStringLiteral( "bbox" ), QStringLiteral( "%1,%2,%3,%4" ).arg( viewExtent.xMinimum(), 0, 'f', -1 ).arg( viewExtent.yMinimum(), 0, 'f', -1 ).arg( viewExtent.xMaximum(), 0, 'f', -1 ).arg( viewExtent.yMaximum(), 0, 'f', -1 ) );
requestUrl.addQueryItem( QStringLiteral( "size" ), QStringLiteral( "%1,%2" ).arg( pixelWidth ).arg( pixelHeight ) );
requestUrl.addQueryItem( QStringLiteral( "format" ), dataSource.param( QStringLiteral( "format" ) ) );
requestUrl.addQueryItem( QStringLiteral( "layers" ), QStringLiteral( "show:%1" ).arg( dataSource.param( QStringLiteral( "layer" ) ) ) );
requestUrl.addQueryItem( QStringLiteral( "transparent" ), QStringLiteral( "true" ) );
requestUrl.addQueryItem( QStringLiteral( "f" ), QStringLiteral( "image" ) );
mError.clear();
mErrorTitle.clear();
QString contentType;
QByteArray reply = QgsArcGisRestUtils::queryService( requestUrl, authcfg, mErrorTitle, mError, mRequestHeaders, feedback, &contentType );
if ( !mError.isEmpty() )
{
mCachedImage = QImage();
if ( feedback )
feedback->appendError( QStringLiteral( "%1: %2" ).arg( mErrorTitle, mError ) );
return QImage();
}
else if ( contentType.startsWith( QLatin1String( "application/json" ) ) )
{
// if we get a JSON response, something went wrong (e.g. authentication error)
mCachedImage = QImage();
mCachedImage = QImage( pixelWidth, pixelHeight, QImage::Format_ARGB32 );
mCachedImage.fill( Qt::transparent );
QPainter p( &mCachedImage );

QJsonParseError err;
QJsonDocument doc = QJsonDocument::fromJson( reply, &err );
if ( doc.isNull() )
{
mErrorTitle = QObject::tr( "Error" );
mError = reply;
}
else
int maxWidth = mMaxImageWidth > 0 ? mMaxImageWidth : pixelWidth;
int maxHeight = mMaxImageHeight > 0 ? mMaxImageHeight : pixelHeight;
int nbStepWidth = std::ceil( ( float )pixelWidth / maxWidth );
int nbStepHeight = std::ceil( ( float )pixelHeight / maxHeight );
for ( int currentStepWidth = 0; currentStepWidth < nbStepWidth; currentStepWidth++ )
{
for ( int currentStepHeight = 0; currentStepHeight < nbStepHeight; currentStepHeight++ )
{
const QVariantMap res = doc.object().toVariantMap();
if ( res.contains( QStringLiteral( "error" ) ) )
int width = currentStepWidth == nbStepWidth - 1 ? pixelWidth % maxWidth : maxWidth;
int height = currentStepHeight == nbStepHeight - 1 ? pixelHeight % maxHeight : maxHeight;
QgsRectangle extent;
extent.setXMinimum( viewExtent.xMinimum() + viewExtent.width() / pixelWidth * ( currentStepWidth * maxWidth ) );
extent.setXMaximum( viewExtent.xMinimum() + viewExtent.width() / pixelWidth * ( currentStepWidth * maxWidth + width ) );
extent.setYMinimum( viewExtent.yMinimum() + viewExtent.height() / pixelHeight * ( currentStepHeight * maxHeight ) );
extent.setYMaximum( viewExtent.yMinimum() + viewExtent.height() / pixelHeight * ( currentStepHeight * maxHeight + height ) );

QUrl requestUrl( dataSource.param( QStringLiteral( "url" ) ) + ( mImageServer ? "/exportImage" : "/export" ) );
requestUrl.addQueryItem( QStringLiteral( "bbox" ), QStringLiteral( "%1,%2,%3,%4" ).arg( extent.xMinimum(), 0, 'f', -1 ).arg( extent.yMinimum(), 0, 'f', -1 ).arg( extent.xMaximum(), 0, 'f', -1 ).arg( extent.yMaximum(), 0, 'f', -1 ) );
requestUrl.addQueryItem( QStringLiteral( "size" ), QStringLiteral( "%1,%2" ).arg( width ).arg( height ) );
requestUrl.addQueryItem( QStringLiteral( "format" ), dataSource.param( QStringLiteral( "format" ) ) );
requestUrl.addQueryItem( QStringLiteral( "layers" ), QStringLiteral( "show:%1" ).arg( dataSource.param( QStringLiteral( "layer" ) ) ) );
requestUrl.addQueryItem( QStringLiteral( "transparent" ), QStringLiteral( "true" ) );
requestUrl.addQueryItem( QStringLiteral( "f" ), QStringLiteral( "image" ) );
mError.clear();
mErrorTitle.clear();
QString contentType;
QByteArray reply = QgsArcGisRestUtils::queryService( requestUrl, authcfg, mErrorTitle, mError, mRequestHeaders, feedback, &contentType );
if ( !mError.isEmpty() )
{
const QVariantMap error = res.value( QStringLiteral( "error" ) ).toMap();
mError = error.value( QStringLiteral( "message" ) ).toString();
mErrorTitle = QObject::tr( "Error %1" ).arg( error.value( QStringLiteral( "code" ) ).toString() );
mCachedImage = QImage();
if ( feedback )
feedback->appendError( QStringLiteral( "%1: %2" ).arg( mErrorTitle, mError ) );
return QImage();
}
}
else if ( contentType.startsWith( QLatin1String( "application/json" ) ) )
{
// if we get a JSON response, something went wrong (e.g. authentication error)
mCachedImage = QImage();

if ( feedback )
feedback->appendError( QStringLiteral( "%1: %2" ).arg( mErrorTitle, mError ) );
return QImage();
}
else
{
mCachedImage = QImage::fromData( reply, dataSource.param( QStringLiteral( "format" ) ).toLatin1() );
if ( mCachedImage.format() != QImage::Format_ARGB32 )
{
mCachedImage = mCachedImage.convertToFormat( QImage::Format_ARGB32 );
QJsonParseError err;
QJsonDocument doc = QJsonDocument::fromJson( reply, &err );
if ( doc.isNull() )
{
mErrorTitle = QObject::tr( "Error" );
mError = reply;
}
else
{
const QVariantMap res = doc.object().toVariantMap();
if ( res.contains( QStringLiteral( "error" ) ) )
{
const QVariantMap error = res.value( QStringLiteral( "error" ) ).toMap();
mError = error.value( QStringLiteral( "message" ) ).toString();
mErrorTitle = QObject::tr( "Error %1" ).arg( error.value( QStringLiteral( "code" ) ).toString() );
}
}

if ( feedback )
feedback->appendError( QStringLiteral( "%1: %2" ).arg( mErrorTitle, mError ) );
return QImage();
}
else
{
QImage img = QImage::fromData( reply, dataSource.param( QStringLiteral( "format" ) ).toLatin1() );
p.drawImage( QPoint( currentStepWidth * maxWidth, currentStepHeight * maxHeight ), img );
}
}
return mCachedImage;
}
p.end();
return mCachedImage;
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/providers/arcgisrest/qgsamsprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ class QgsAmsProvider : public QgsRasterDataProvider
int mTileReqNo = 0;
bool mTiled = false;
bool mImageServer = false;
int mMaxImageWidth = 4096;
int mMaxImageHeight = 4096;
QgsLayerMetadata mLayerMetadata;
QList< double > mResolutions;
};
Expand Down

0 comments on commit 192c456

Please sign in to comment.