Skip to content
Permalink
Browse files

Merge pull request #38355 from nyalldawson/svg_ratio

Fix bad handling of non-square svg images in svg marker symbol layers
  • Loading branch information
nyalldawson committed Aug 19, 2020
2 parents 4aefe0d + 0864e0a commit c0990ea05e9facfa8660b29919ff15709da7c4e1
@@ -1906,6 +1906,7 @@ void QgsSvgMarkerSymbolLayer::resolvePaths( QgsStringMap &properties, const QgsP

void QgsSvgMarkerSymbolLayer::setPath( const QString &path )
{
mDefaultAspectRatio = 0;
mPath = path;
QColor defaultFillColor, defaultStrokeColor;
double strokeWidth, fillOpacity, strokeOpacity;
@@ -348,7 +348,31 @@ double QgsSvgCache::calcSizeScaleFactor( QgsSvgCacheEntry *entry, const QDomElem

//could not find valid viewbox attribute
if ( viewBox.isEmpty() )
{
// trying looking for width/height and use them as a fallback
if ( docElem.tagName() == QLatin1String( "svg" ) && docElem.hasAttribute( QStringLiteral( "width" ) ) )
{
const QString widthString = docElem.attribute( QStringLiteral( "width" ) );
const QRegularExpression measureRegEx( QStringLiteral( "([\\d\\.]+).*?$" ) );
const QRegularExpressionMatch widthMatch = measureRegEx.match( widthString );
if ( widthMatch.hasMatch() )
{
double width = widthMatch.captured( 1 ).toDouble();
const QString heightString = docElem.attribute( QStringLiteral( "height" ) );

const QRegularExpressionMatch heightMatch = measureRegEx.match( heightString );
if ( heightMatch.hasMatch() )
{
double height = heightMatch.captured( 1 ).toDouble();
viewboxSize = QSizeF( width, height );
return width / entry->size;
}
}
}

return 1.0;
}


//width should be 3rd element in a 4 part space delimited string
QStringList parts = viewBox.split( ' ' );
@@ -2456,7 +2456,7 @@ void QgsSvgMarkerSymbolLayerWidget::setGuiForSvg( const QgsSvgMarkerSymbolLayer
spinHeight->blockSignals( true );
if ( preservedAspectRatio )
{
spinHeight->setValue( layer->size() );
spinHeight->setValue( layer->size() * layer->defaultAspectRatio() );
}
else
{
@@ -55,6 +55,7 @@ class TestQgsSvgCache : public QObject
void base64();
void replaceParams();
void aspectRatio();
void noViewBox();

};

@@ -345,6 +346,22 @@ void TestQgsSvgCache::aspectRatio()
QVERIFY( imageCheck( QStringLiteral( "svgcache_aspect_ratio" ), img, 30 ) );
}

void TestQgsSvgCache::noViewBox()
{
// if a source SVG has no viewbox but it does have width/height, use that as a backup so that
// we can correctly determine the svg's aspect ratio
const QString originalImage = TEST_DATA_DIR + QStringLiteral( "/svg/no_viewbox.svg" );
QgsSvgCache cache;
double size = 12;
const QColor fill = QColor( 0, 0, 0 );
const QColor stroke = QColor( 0, 0, 0 );
double strokeWidth = 1;
double widthScaleFactor = 1;
QSizeF viewBoxSize = cache.svgViewboxSize( originalImage, size, fill, stroke, strokeWidth, widthScaleFactor );
QGSCOMPARENEAR( viewBoxSize.width(), 1.329267, 0.0001 );
QGSCOMPARENEAR( viewBoxSize.height(), 6.358467, 0.0001 );
}

bool TestQgsSvgCache::imageCheck( const QString &testName, QImage &image, int mismatchCount )
{
//draw background
@@ -62,6 +62,7 @@ class TestQgsSvgMarkerSymbol : public QObject
void dynamicSizeWithAspectRatio();
void dynamicWidthWithAspectRatio();
void dynamicAspectRatio();
void resetDefaultAspectRatio();

private:
bool mTestHasError = false ;
@@ -252,6 +253,33 @@ void TestQgsSvgMarkerSymbol::dynamicAspectRatio()
QVERIFY( result );
}

void TestQgsSvgMarkerSymbol::resetDefaultAspectRatio()
{
// default aspect ratio must be updated as SVG path is changed
QString svgPath = QgsSymbolLayerUtils::svgSymbolNameToPath( QStringLiteral( "/amenity/amenity_bench.svg" ), QgsPathResolver() );
QgsSvgMarkerSymbolLayer layer( svgPath );
QCOMPARE( layer.defaultAspectRatio(), 1.0 );
QVERIFY( layer.preservedAspectRatio() );

// different aspect ratio
layer.setPath( mTestDataDir + "test_symbol_svg.svg" );
QGSCOMPARENEAR( layer.defaultAspectRatio(), 1.58258242005, 0.0001 );
QVERIFY( layer.preservedAspectRatio() );
layer.setPath( svgPath );
QCOMPARE( layer.defaultAspectRatio(), 1.0 );
QVERIFY( layer.preservedAspectRatio() );

layer.setFixedAspectRatio( 0.5 );
QCOMPARE( layer.defaultAspectRatio(), 1.0 );
QCOMPARE( layer.fixedAspectRatio(), 0.5 );
QVERIFY( !layer.preservedAspectRatio() );

layer.setPath( mTestDataDir + "test_symbol_svg.svg" );
QGSCOMPARENEAR( layer.defaultAspectRatio(), 1.58258242005, 0.0001 );
QCOMPARE( layer.fixedAspectRatio(), 0.5 );
QVERIFY( !layer.preservedAspectRatio() );
}

//
// Private helper functions not called directly by CTest
//
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg13"
height="6.3584666mm"
width="1.3292667mm"
version="1.0">
<metadata
id="metadata17">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3">
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern" />
</defs>
<path
id="path5"
d=" M 0.66666667,0 L 0.66666667,24 z "
style="fill:#ffffff;fill-rule:nonzero;fill-opacity:1;stroke:none;" />
<path
id="path7"
d=" M 0.66666667,0 L 0.66666667,24 "
style="fill:none;stroke:#000000;stroke-width:0.66666669px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1;" />
<path
id="path9"
d=" M 0.66666667,8 C 3,8 5,9.6666667 5,12 C 5,14.333333 3,16 0.66666667,16 "
style="fill:none;stroke:#000000;stroke-width:0.66666669px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1;" />
<path
id="path11"
d=" M 0.66666667,12 L 5,12 "
style="fill:none;stroke:#000000;stroke-width:0.66666669px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1;" />
</svg>

0 comments on commit c0990ea

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