Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export parametric SVG, will fallback symbols for the systems that cannot understand them #3703

Merged
merged 1 commit into from
Nov 11, 2016

Conversation

aaime
Copy link
Contributor

@aaime aaime commented Nov 1, 2016

This pull request makes the SVG parameters explicit, but at the same time leverages SLD fallback symbol support to add a non parametric SVG fallback, as well as a simple mark with the right color and outline for systems that cannot deal with SVG, or lack the symbol on their file system.

@@ -2093,12 +2095,6 @@ void QgsSVGFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, cons
symbolizerElem.appendChild( doc.createComment( QStringLiteral( "SVG from data not implemented yet" ) ) );
}

if ( mSvgOutlineColor.isValid() || mSvgOutlineWidth >= 0 )
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was removed as the svg outline is not the same thing as the polygon fill outline

@aaime aaime changed the title Export parametric SVG, will fallback symbols for the system that cannot understand them Export parametric SVG, will fallback symbols for the systems that cannot understand them Nov 1, 2016
Copy link
Collaborator

@nyalldawson nyalldawson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few minor suggestions, but this looks good in general to me! Will be very nice to have!

* that cannot do SVG at all
* @note added in 3.0
*/
static void parametricSvgToSld( QDomDocument &doc, QDomElement &graphicElem,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest:

  1. Rename color to fillColor
  2. Make this return the QDomElement instead of passing it as an argument

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally don't have a strong preference for either, but the vast majority of the xml writing methods in QGIS return the element. So my vote goes to consistency :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had another look and believe it should be kept as is. Here is an example of calling code:

void QgsSvgMarkerSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &element, const QgsStringMap& props ) const
{
  // <Graphic>
  QDomElement graphicElem = doc.createElement( QStringLiteral( "se:Graphic" ) );
  element.appendChild( graphicElem );

  // encode a parametric SVG reference
  double size = QgsSymbolLayerUtils::rescaleUom( mSize, mSizeUnit, props );
  double outlineWidth = QgsSymbolLayerUtils::rescaleUom( mOutlineWidth, mOutlineWidthUnit, props );
  QgsSymbolLayerUtils::parametricSvgToSld( doc, graphicElem, mPath, mColor, size, mOutlineColor, outlineWidth );

  // <Rotation>
  QString angleFunc;
  bool ok;
  double angle = props.value( QStringLiteral( "angle" ), QStringLiteral( "0" ) ).toDouble( &ok );
  if ( !ok )
  {
    angleFunc = QStringLiteral( "%1 + %2" ).arg( props.value( QStringLiteral( "angle" ), QStringLiteral( "0" ) ) ).arg( mAngle );
  }
  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
  {
    angleFunc = QString::number( angle + mAngle );
  }

  QgsSymbolLayerUtils::createRotationElement( doc, graphicElem, angleFunc );

  // <Displacement>
  QPointF offset = QgsSymbolLayerUtils::rescaleUom( mOffset, mOffsetUnit, props );
  QgsSymbolLayerUtils::createDisplacementElement( doc, graphicElem, offset );
}

As you can see the pattern of passing "doc and element" is spread across the whole method, and parametricSvgToSld is not the only contributor to the creation of graphic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nyalldawson what do you think? I can still change that to break the existing pattern and build the element instead of accepting it... it would just look odd in the context where it's used, not the end of the world I presume ;-)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aaime - no, it's all good. your reasoning is sound!

{
url.addQueryItem( "outline", borderColor.name() );
url.addQueryItem( "outline-opacity", encodeSldAlpha( borderColor.alpha() ) );
url.addQueryItem( "outline-width", QString::number( borderWidth ) );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's possible that an svg could use the outline-width parameter without having an outline-color. Actually that applies to all parameters, eg fill opacity without paramaterised fill colors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix that

@aaime
Copy link
Contributor Author

aaime commented Nov 5, 2016

Pushed some fixes:

  • fillColor instead of color
  • encode width param anyways
  • if a color is not valid in svg params, use black as a fallback to ensure all params are always encoded.

By the way, I noticed that the SVG param expansion code seems to assume colors are never invalid, I don't see checks.

QString QgsSymbolLayerUtils::getSvgParametricPath( const QString& basePath, const QColor& fillColor, const QColor& borderColor, double borderWidth )
{
QUrl url = QUrl();
if ( fillColor.isValid() )
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These also should be split up - eg you could potentially use 'fill-opacity' without any 'fill' parameter for a multi-colored fill svg. (same with outline opacity).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hum hum... how is that done though? The existing callers only have a QColor, which embodies both color and opacity. You mean it would be better to have a string (encoded color) and a opacity (number) for each color, so that the caller can decide which parameters are going to be replaced?

As noted before, the actual rendering code seems to just assume colors are always present and valid, which is a bit strange, but I did not yet play with the UI and see if the fill can be excluded, and how.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah... ignore me.... i was confused.

@nyalldawson nyalldawson merged commit 1ef7ed5 into qgis:master Nov 11, 2016
@aaime
Copy link
Contributor Author

aaime commented Nov 13, 2016

Thank you @nyalldawson !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants