Skip to content
Permalink
Browse files

[FEATURE] Add option to force a vector layer to render as a raster

(under the layer properties, rendering tab)

So why would you want this? Well, extremely detailed layers (eg
polygon layers with a huge number of nodes) can cause composer
exports in PDF/SVG format to be huge as all nodes are included in
the exported file. This can also make the resultant file very slow
to work with/open in other programs (*cough* Inkscape *cough*).

Now, these you can force these layers to be rasterised so that the
exported files won't have to include all the nodes contained in these
layers. (Before you could also do this by forcing the composer to
export as a raster, but that was an all-or-nothing solution).

The ideal solution would be a simplification option for composer
exports which would simplify the layers by removing redundant points
at the export DPI, but this is an easy workaround for now.
  • Loading branch information
nyalldawson committed Jul 9, 2015
1 parent a9e9f86 commit cfee456c053a4da67b360f085c5cf3b0ee13ddb0
@@ -211,6 +211,21 @@ class QgsFeatureRendererV2
*/
void setPaintEffect( QgsPaintEffect* effect /Transfer/);

/** Returns whether the renderer must render as a raster.
* @note added in QGIS 2.12
* @see setForceRasterRender
*/
bool forceRasterRender() const;

/** Sets whether the renderer should be rendered to a raster destination.
* @param forceRaster set to true if renderer must be drawn on a raster surface.
* This may be desirable for highly detailed layers where rendering as a vector
* would result in a large, complex vector output.
* @see forceRasterRender
* @note added in QGIS 2.12
*/
void setForceRasterRender( bool forceRaster );

protected:
QgsFeatureRendererV2( QString type );

@@ -49,6 +49,7 @@
#include "qgsvectordataprovider.h"
#include "qgsquerybuilder.h"
#include "qgsdatasourceuri.h"
#include "qgsrendererv2.h"

#include <QMessageBox>
#include <QDir>
@@ -435,15 +436,17 @@ void QgsVectorLayerProperties::syncToLayer( void )
// disable simplification for point layers, now it is not implemented
if ( layer->geometryType() == QGis::Point )
{
mOptionsStackedWidget->removeWidget( mOptsPage_Rendering );
mSimplifyDrawingGroupBox->setChecked( false );
mSimplifyDrawingGroupBox->setEnabled( false );
}

QStringList myScalesList = PROJECT_SCALES.split( "," );
myScalesList.append( "1:1" );
mSimplifyMaximumScaleComboBox->updateScales( myScalesList );
mSimplifyMaximumScaleComboBox->setScale( 1.0 / simplifyMethod.maximumScale() );

mForceRasterCheckBox->setChecked( layer->rendererV2() && layer->rendererV2()->forceRasterRender() );

// load appropriate symbology page (V1 or V2)
updateSymbologyPage();

@@ -602,6 +605,9 @@ void QgsVectorLayerProperties::apply()
simplifyMethod.setMaximumScale( 1.0 / mSimplifyMaximumScaleComboBox->scale() );
layer->setSimplifyMethod( simplifyMethod );

if ( layer->rendererV2() )
layer->rendererV2()->setForceRasterRender( mForceRasterCheckBox->isChecked() );

mOldJoins = layer->vectorJoins();

// update symbology
@@ -20,6 +20,7 @@
#include "qgsmaplayerrenderer.h"
#include "qgspallabeling.h"
#include "qgsvectorlayer.h"
#include "qgsrendererv2.h"

QgsMapRendererCustomPainterJob::QgsMapRendererCustomPainterJob( const QgsMapSettings& settings, QPainter* painter )
: QgsMapRendererJob( settings )
@@ -338,13 +339,22 @@ void QgsMapRendererJob::updateLayerGeometryCaches()

bool QgsMapRendererJob::needTemporaryImage( QgsMapLayer* ml )
{
if ( mSettings.testFlag( QgsMapSettings::UseAdvancedEffects ) && ml->type() == QgsMapLayer::VectorLayer )
if ( ml->type() == QgsMapLayer::VectorLayer )
{
QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml );
if ((( vl->blendMode() != QPainter::CompositionMode_SourceOver )
|| ( vl->featureBlendMode() != QPainter::CompositionMode_SourceOver )
|| ( vl->layerTransparency() != 0 ) ) )
if ( vl->rendererV2()->forceRasterRender() )
{
//raster rendering is forced for this layer
return true;
}
if ( mSettings.testFlag( QgsMapSettings::UseAdvancedEffects ) &&
(( vl->blendMode() != QPainter::CompositionMode_SourceOver )
|| ( vl->featureBlendMode() != QPainter::CompositionMode_SourceOver )
|| ( vl->layerTransparency() != 0 ) ) )
{
//layer properties require rasterisation
return true;
}
}

return false;
@@ -626,6 +626,7 @@ QDomElement QgsCategorizedSymbolRendererV2::save( QDomDocument& doc )
QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
rendererElem.setAttribute( "type", "categorizedSymbol" );
rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
rendererElem.setAttribute( "forceraster", ( mForceRaster ? "1" : "0" ) );
rendererElem.setAttribute( "attr", mAttrName );

// categories
@@ -1071,6 +1071,7 @@ QDomElement QgsGraduatedSymbolRendererV2::save( QDomDocument& doc )
QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
rendererElem.setAttribute( "type", "graduatedSymbol" );
rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
rendererElem.setAttribute( "forceraster", ( mForceRaster ? "1" : "0" ) );
rendererElem.setAttribute( "attr", mAttrName );
rendererElem.setAttribute( "graduatedMethod", graduatedMethodStr( mGraduatedMethod ) );

@@ -360,6 +360,7 @@ QDomElement QgsInvertedPolygonRenderer::save( QDomDocument& doc )
QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
rendererElem.setAttribute( "type", "invertedPolygonRenderer" );
rendererElem.setAttribute( "preprocessing", preprocessingEnabled() ? "1" : "0" );
rendererElem.setAttribute( "forceraster", ( mForceRaster ? "1" : "0" ) );

if ( mSubRenderer )
{
@@ -370,6 +370,7 @@ QgsFeatureRendererV2* QgsPointDisplacementRenderer::create( QDomElement& symbolo
QDomElement QgsPointDisplacementRenderer::save( QDomDocument& doc )
{
QDomElement rendererElement = doc.createElement( RENDERER_TAG_NAME );
rendererElement.setAttribute( "forceraster", ( mForceRaster ? "1" : "0" ) );
rendererElement.setAttribute( "type", "pointDisplacement" );
rendererElement.setAttribute( "labelAttributeName", mLabelAttributeName );
rendererElement.appendChild( QgsFontUtils::toXmlElement( mLabelFont, doc, "labelFontProperties" ) );
@@ -209,6 +209,7 @@ QgsFeatureRendererV2::QgsFeatureRendererV2( QString type )
, mCurrentVertexMarkerType( QgsVectorLayer::Cross )
, mCurrentVertexMarkerSize( 3 )
, mPaintEffect( 0 )
, mForceRaster( false )
{
mPaintEffect = QgsPaintEffectRegistry::defaultStack();
mPaintEffect->setEnabled( false );
@@ -423,6 +424,7 @@ QgsFeatureRendererV2* QgsFeatureRendererV2::load( QDomElement& element )
if ( r )
{
r->setUsingSymbolLevels( element.attribute( "symbollevels", "0" ).toInt() );
r->setForceRasterRender( element.attribute( "forceraster", "0" ).toInt() );

//restore layer effect
QDomElement effectElem = element.firstChildElement( "effect" );
@@ -438,6 +440,7 @@ QDomElement QgsFeatureRendererV2::save( QDomDocument& doc )
{
// create empty renderer element
QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
rendererElem.setAttribute( "forceraster", ( mForceRaster ? "1" : "0" ) );

if ( mPaintEffect )
mPaintEffect->saveProperties( doc, rendererElem );
@@ -81,7 +81,7 @@ class CORE_EXPORT QgsFeatureRendererV2

QString type() const { return mType; }

/** to be overridden
/** To be overridden
* @param feature feature
* @return returns pointer to symbol or 0 if symbol was not found
*/
@@ -144,7 +144,7 @@ class CORE_EXPORT QgsFeatureRendererV2
//! @note added in 2.8
virtual QDomElement writeSld( QDomDocument& doc, const QString& styleName ) const;

/** create a new renderer according to the information contained in
/** Create a new renderer according to the information contained in
* the UserStyle element of a SLD style document
* @param node the node in the SLD document whose the UserStyle element
* is a child
@@ -211,7 +211,7 @@ class CORE_EXPORT QgsFeatureRendererV2
//! @note added in 2.6
virtual QgsSymbolV2List originalSymbolsForFeature( QgsFeature& feat );

/**Allows for a renderer to modify the extent of a feature request prior to rendering
/** Allows for a renderer to modify the extent of a feature request prior to rendering
* @param extent reference to request's filter extent. Modify extent to change the
* extent of feature request
* @param context render context
@@ -233,6 +233,21 @@ class CORE_EXPORT QgsFeatureRendererV2
*/
void setPaintEffect( QgsPaintEffect* effect );

/** Returns whether the renderer must render as a raster.
* @note added in QGIS 2.12
* @see setForceRasterRender
*/
bool forceRasterRender() const { return mForceRaster; }

/** Sets whether the renderer should be rendered to a raster destination.
* @param forceRaster set to true if renderer must be drawn on a raster surface.
* This may be desirable for highly detailed layers where rendering as a vector
* would result in a large, complex vector output.
* @see forceRasterRender
* @note added in QGIS 2.12
*/
void setForceRasterRender( bool forceRaster ) { mForceRaster = forceRaster; }

protected:
QgsFeatureRendererV2( QString type );

@@ -272,11 +287,13 @@ class CORE_EXPORT QgsFeatureRendererV2

QgsPaintEffect* mPaintEffect;

/**@note this function is used to convert old sizeScale expresssions to symbol
bool mForceRaster;

/** @note this function is used to convert old sizeScale expresssions to symbol
* level DataDefined size
*/
static void convertSymbolSizeScale( QgsSymbolV2 * symbol, QgsSymbolV2::ScaleMethod method, const QString & field );
/**@note this function is used to convert old rotations expresssions to symbol
/** @note this function is used to convert old rotations expresssions to symbol
* level DataDefined angle
*/
static void convertSymbolRotation( QgsSymbolV2 * symbol, const QString & field );
@@ -885,6 +885,7 @@ QDomElement QgsRuleBasedRendererV2::save( QDomDocument& doc )
QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
rendererElem.setAttribute( "type", "RuleRenderer" );
rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
rendererElem.setAttribute( "forceraster", ( mForceRaster ? "1" : "0" ) );

QgsSymbolV2Map symbols;

@@ -344,6 +344,7 @@ QDomElement QgsSingleSymbolRendererV2::save( QDomDocument& doc )
QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
rendererElem.setAttribute( "type", "singleSymbol" );
rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
rendererElem.setAttribute( "forceraster", ( mForceRaster ? "1" : "0" ) );

QgsSymbolV2Map symbols;
symbols["0"] = mSymbol.data();
@@ -692,8 +692,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>123</width>
<height>38</height>
<width>730</width>
<height>537</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_28">
@@ -774,8 +774,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>100</width>
<height>30</height>
<width>730</width>
<height>537</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_20">
@@ -834,8 +834,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>721</width>
<height>171</height>
<width>730</width>
<height>537</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_32">
@@ -940,6 +940,13 @@
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="mForceRasterCheckBox">
<property name="text">
<string>Force layer to render as a raster (may result in smaller export file sizes)</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_6">
<property name="orientation">
@@ -1400,7 +1407,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>393</width>
<width>714</width>
<height>608</height>
</rect>
</property>
@@ -1801,7 +1808,6 @@
</customwidget>
</customwidgets>
<tabstops>
<tabstop>buttonBox</tabstop>
<tabstop>mOptionsListWidget</tabstop>
<tabstop>scrollArea</tabstop>
<tabstop>mLayerOrigNameLineEdit</tabstop>
@@ -1823,7 +1829,7 @@
<tabstop>mSimplifyDrawingSpinBox</tabstop>
<tabstop>mSimplifyDrawingAtProvider</tabstop>
<tabstop>mSimplifyMaximumScaleComboBox</tabstop>
<tabstop>scrollArea_10</tabstop>
<tabstop>mForceRasterCheckBox</tabstop>
<tabstop>fieldComboRadio</tabstop>
<tabstop>displayFieldComboBox</tabstop>
<tabstop>htmlRadio</tabstop>
@@ -1836,7 +1842,6 @@
<tabstop>scrollArea_7</tabstop>
<tabstop>mButtonAddJoin</tabstop>
<tabstop>mButtonRemoveJoin</tabstop>
<tabstop>mDiagramFrame</tabstop>
<tabstop>scrollArea_2</tabstop>
<tabstop>mLayerTitleLineEdit</tabstop>
<tabstop>mLayerAbstractTextEdit</tabstop>
@@ -1851,6 +1856,8 @@
<tabstop>mLayerLegendUrlLineEdit</tabstop>
<tabstop>mLayerLegendUrlFormatComboBox</tabstop>
<tabstop>teMetadata</tabstop>
<tabstop>mButtonEditJoin</tabstop>
<tabstop>scrollArea_10</tabstop>
</tabstops>
<resources>
<include location="../../images/images.qrc"/>

3 comments on commit cfee456

@nirvn

This comment has been minimized.

Copy link
Contributor

@nirvn nirvn replied Jul 9, 2015

Wouhou. Thanks

@andremano

This comment has been minimized.

Copy link

@andremano andremano replied Jul 9, 2015

Thanks!

@jonnyforestGIS

This comment has been minimized.

Copy link
Contributor

@jonnyforestGIS jonnyforestGIS replied Jul 9, 2015

Nice Nyall! Regards

Please sign in to comment.
You can’t perform that action at this time.