Skip to content

Commit

Permalink
Add fixedAspectRatio in QgsSvgCacheEntry and compute image size accor…
Browse files Browse the repository at this point in the history
…dingly
  • Loading branch information
dmarteau authored and rldhont committed Sep 28, 2017
1 parent f9f5aaf commit 740ccbe
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 32 deletions.
22 changes: 15 additions & 7 deletions python/core/symbology/qgssvgcache.sip
Expand Up @@ -18,9 +18,11 @@ class QgsSvgCacheEntry
#include "qgssvgcache.h"
%End
public:

QgsSvgCacheEntry();

QgsSvgCacheEntry( const QString &path, double size, double strokeWidth, double widthScaleFactor, const QColor &fill, const QColor &stroke );
QgsSvgCacheEntry( const QString &path, double size, double strokeWidth, double widthScaleFactor, const QColor &fill, const QColor &stroke,
double fixedAspectRatio = 0 ) ;
%Docstring
Constructor.
\param path Absolute path to SVG file (relative paths are not resolved).
Expand All @@ -29,6 +31,7 @@ class QgsSvgCacheEntry
\param widthScaleFactor width scale factor
\param fill color of fill
\param stroke color of stroke
\param fixedAspectRatio fixed aspect ratio (optional)
%End
~QgsSvgCacheEntry();

Expand All @@ -41,6 +44,11 @@ Absolute path to SVG file
double strokeWidth;
double widthScaleFactor;

double fixedAspectRatio;
%Docstring
Fixed aspect ratio
%End

QSizeF viewboxSize;
%Docstring
SVG viewbox size.
Expand Down Expand Up @@ -91,7 +99,7 @@ the parameters 'fill-color', 'pen-color', 'outline-width', 'stroke-width'. E.g.
~QgsSvgCache();

QImage svgAsImage( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth,
double widthScaleFactor, bool &fitsInCache );
double widthScaleFactor, bool &fitsInCache, double fixedAspectRatio = 0 );
%Docstring
Get SVG as QImage.
\param path Absolute path to SVG file.
Expand All @@ -105,7 +113,7 @@ the parameters 'fill-color', 'pen-color', 'outline-width', 'stroke-width'. E.g.
%End

QPicture svgAsPicture( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth,
double widthScaleFactor, bool forceVectorOutput = false );
double widthScaleFactor, bool forceVectorOutput = false, double fixedAspectRatio = 0 );
%Docstring
Get SVG as QPicture&.
\param path Absolute path to SVG file.
Expand All @@ -119,7 +127,7 @@ the parameters 'fill-color', 'pen-color', 'outline-width', 'stroke-width'. E.g.
%End

QSizeF svgViewboxSize( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth,
double widthScaleFactor );
double widthScaleFactor, double fixedAspectRatio = 0 );
%Docstring
Calculates the viewbox size of a (possibly cached) SVG file.
\param path Absolute path to SVG file.
Expand Down Expand Up @@ -177,7 +185,7 @@ Get image data
%End

QByteArray svgContent( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth,
double widthScaleFactor );
double widthScaleFactor, double fixedAspectRatio = 0);
%Docstring
Get SVG content
:rtype: QByteArray
Expand All @@ -192,7 +200,7 @@ Emit a signal to be caught by qgisapp and display a msg on status bar
protected:

QgsSvgCacheEntry *insertSvg( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth,
double widthScaleFactor );
double widthScaleFactor, double fixedAspectRatio = 0 );
%Docstring
Creates new cache entry and returns pointer to it
\param path Absolute path to SVG file
Expand All @@ -208,7 +216,7 @@ Emit a signal to be caught by qgisapp and display a msg on status bar
void cacheImage( QgsSvgCacheEntry *entry );
void cachePicture( QgsSvgCacheEntry *entry, bool forceVectorOutput = false );
QgsSvgCacheEntry *cacheEntry( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth,
double widthScaleFactor );
double widthScaleFactor, double fixedAspectRatio = 0 );
%Docstring
Returns entry from cache or creates a new entry if it does not exist already
:rtype: QgsSvgCacheEntry
Expand Down
64 changes: 46 additions & 18 deletions src/core/symbology/qgssvgcache.cpp
Expand Up @@ -43,11 +43,12 @@ QgsSvgCacheEntry::QgsSvgCacheEntry()
{
}

QgsSvgCacheEntry::QgsSvgCacheEntry( const QString &p, double s, double ow, double wsf, const QColor &fi, const QColor &ou )
QgsSvgCacheEntry::QgsSvgCacheEntry( const QString &p, double s, double ow, double wsf, const QColor &fi, const QColor &ou, double far )
: path( p )
, size( s )
, strokeWidth( ow )
, widthScaleFactor( wsf )
, fixedAspectRatio( far )
, fill( fi )
, stroke( ou )
{
Expand Down Expand Up @@ -93,12 +94,12 @@ QgsSvgCache::~QgsSvgCache()


QImage QgsSvgCache::svgAsImage( const QString &file, double size, const QColor &fill, const QColor &stroke, double strokeWidth,
double widthScaleFactor, bool &fitsInCache )
double widthScaleFactor, bool &fitsInCache, double fixedAspectRatio )
{
QMutexLocker locker( &mMutex );

fitsInCache = true;
QgsSvgCacheEntry *currentEntry = cacheEntry( file, size, fill, stroke, strokeWidth, widthScaleFactor );
QgsSvgCacheEntry *currentEntry = cacheEntry( file, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio );

//if current entry image is 0: cache image for entry
// checks to see if image will fit into cache
Expand All @@ -109,7 +110,14 @@ QImage QgsSvgCache::svgAsImage( const QString &file, double size, const QColor &
double hwRatio = 1.0;
if ( r.viewBoxF().width() > 0 )
{
hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
if( currentEntry->fixedAspectRatio > 0 )
{
hwRatio = currentEntry->fixedAspectRatio;
}
else
{
hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
}
}
long cachedDataSize = 0;
cachedDataSize += currentEntry->svgContent.size();
Expand Down Expand Up @@ -138,11 +146,11 @@ QImage QgsSvgCache::svgAsImage( const QString &file, double size, const QColor &
}

QPicture QgsSvgCache::svgAsPicture( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth,
double widthScaleFactor, bool forceVectorOutput )
double widthScaleFactor, bool forceVectorOutput, double fixedAspectRatio )
{
QMutexLocker locker( &mMutex );

QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor );
QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio );

//if current entry picture is 0: cache picture for entry
//update stats for memory usage
Expand All @@ -156,28 +164,28 @@ QPicture QgsSvgCache::svgAsPicture( const QString &path, double size, const QCol
}

QByteArray QgsSvgCache::svgContent( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth,
double widthScaleFactor )
double widthScaleFactor, double fixedAspectRatio )
{
QMutexLocker locker( &mMutex );

QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor );
QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio );

return currentEntry->svgContent;
}

QSizeF QgsSvgCache::svgViewboxSize( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor )
QSizeF QgsSvgCache::svgViewboxSize( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor, double fixedAspectRatio )
{
QMutexLocker locker( &mMutex );

QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor );
QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio );

return currentEntry->viewboxSize;
}

QgsSvgCacheEntry *QgsSvgCache::insertSvg( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth,
double widthScaleFactor )
double widthScaleFactor, double fixedAspectRatio )
{
QgsSvgCacheEntry *entry = new QgsSvgCacheEntry( path, size, strokeWidth, widthScaleFactor, fill, stroke );
QgsSvgCacheEntry *entry = new QgsSvgCacheEntry( path, size, strokeWidth, widthScaleFactor, fill, stroke, fixedAspectRatio );

replaceParamsAndCacheSvg( entry );

Expand Down Expand Up @@ -471,11 +479,20 @@ void QgsSvgCache::cacheImage( QgsSvgCacheEntry *entry )
delete entry->image;
entry->image = nullptr;

bool isFixedAR = entry->fixedAspectRatio > 0;

QSvgRenderer r( entry->svgContent );
double hwRatio = 1.0;
if ( r.viewBoxF().width() > 0 )
{
hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
if( isFixedAR )
{
hwRatio = entry->fixedAspectRatio;
}
else
{
hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
}
}
double wSize = entry->size;
int wImgSize = static_cast< int >( wSize );
Expand Down Expand Up @@ -521,20 +538,30 @@ void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry, bool forceVectorOutput
delete entry->picture;
entry->picture = nullptr;

bool isFixedAR = entry->fixedAspectRatio > 0;

//correct QPictures dpi correction
QPicture *picture = new QPicture();
QRectF rect;
QSvgRenderer r( entry->svgContent );
double hwRatio = 1.0;
if ( r.viewBoxF().width() > 0 )
{
hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
if( isFixedAR )
{
hwRatio = entry->fixedAspectRatio;
}
else
{
hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
}
}

double wSize = entry->size;
double hSize = wSize * hwRatio;

QSizeF s( r.viewBoxF().size() );
s.scale( wSize, hSize, Qt::KeepAspectRatio );
s.scale( wSize, hSize, isFixedAR ? Qt::IgnoreAspectRatio : Qt::KeepAspectRatio );
rect = QRectF( -s.width() / 2.0, -s.height() / 2.0, s.width(), s.height() );

QPainter p( picture );
Expand All @@ -544,7 +571,7 @@ void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry, bool forceVectorOutput
}

QgsSvgCacheEntry *QgsSvgCache::cacheEntry( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth,
double widthScaleFactor )
double widthScaleFactor, double fixedAspectRatio )
{
//search entries in mEntryLookup
QgsSvgCacheEntry *currentEntry = nullptr;
Expand All @@ -555,7 +582,8 @@ QgsSvgCacheEntry *QgsSvgCache::cacheEntry( const QString &path, double size, con
{
QgsSvgCacheEntry *cacheEntry = *entryIt;
if ( qgsDoubleNear( cacheEntry->size, size ) && cacheEntry->fill == fill && cacheEntry->stroke == stroke &&
qgsDoubleNear( cacheEntry->strokeWidth, strokeWidth ) && qgsDoubleNear( cacheEntry->widthScaleFactor, widthScaleFactor ) )
qgsDoubleNear( cacheEntry->strokeWidth, strokeWidth ) && qgsDoubleNear( cacheEntry->widthScaleFactor, widthScaleFactor ) &&
qgsDoubleNear( cacheEntry->fixedAspectRatio, fixedAspectRatio ))
{
currentEntry = cacheEntry;
break;
Expand All @@ -566,7 +594,7 @@ QgsSvgCacheEntry *QgsSvgCache::cacheEntry( const QString &path, double size, con
//cache and replace params in svg content
if ( !currentEntry )
{
currentEntry = insertSvg( path, size, fill, stroke, strokeWidth, widthScaleFactor );
currentEntry = insertSvg( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio);
}
else
{
Expand Down
20 changes: 13 additions & 7 deletions src/core/symbology/qgssvgcache.h
Expand Up @@ -40,6 +40,7 @@ class QPicture;
class CORE_EXPORT QgsSvgCacheEntry
{
public:

QgsSvgCacheEntry();

/** Constructor.
Expand All @@ -49,8 +50,10 @@ class CORE_EXPORT QgsSvgCacheEntry
* \param widthScaleFactor width scale factor
* \param fill color of fill
* \param stroke color of stroke
* \param fixedAspectRatio fixed aspect ratio (optional)
*/
QgsSvgCacheEntry( const QString &path, double size, double strokeWidth, double widthScaleFactor, const QColor &fill, const QColor &stroke );
QgsSvgCacheEntry( const QString &path, double size, double strokeWidth, double widthScaleFactor, const QColor &fill, const QColor &stroke,
double fixedAspectRatio = 0 ) ;
~QgsSvgCacheEntry();

//! QgsSvgCacheEntry cannot be copied.
Expand All @@ -64,6 +67,9 @@ class CORE_EXPORT QgsSvgCacheEntry
double strokeWidth = 0;
double widthScaleFactor = 1.0;

//! Fixed aspect ratio
double fixedAspectRatio = 0;

/** SVG viewbox size.
* \since QGIS 2.14
*/
Expand Down Expand Up @@ -123,7 +129,7 @@ class CORE_EXPORT QgsSvgCache : public QObject
* \param fitsInCache
*/
QImage svgAsImage( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth,
double widthScaleFactor, bool &fitsInCache );
double widthScaleFactor, bool &fitsInCache, double fixedAspectRatio = 0 );

/** Get SVG as QPicture&.
* \param path Absolute path to SVG file.
Expand All @@ -135,7 +141,7 @@ class CORE_EXPORT QgsSvgCache : public QObject
* \param forceVectorOutput
*/
QPicture svgAsPicture( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth,
double widthScaleFactor, bool forceVectorOutput = false );
double widthScaleFactor, bool forceVectorOutput = false, double fixedAspectRatio = 0 );

/** Calculates the viewbox size of a (possibly cached) SVG file.
* \param path Absolute path to SVG file.
Expand All @@ -148,7 +154,7 @@ class CORE_EXPORT QgsSvgCache : public QObject
* \since QGIS 2.14
*/
QSizeF svgViewboxSize( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth,
double widthScaleFactor );
double widthScaleFactor, double fixedAspectRatio = 0 );

/** Tests if an svg file contains parameters for fill, stroke color, stroke width. If yes, possible default values are returned. If there are several
default values in the svg file, only the first one is considered*/
Expand Down Expand Up @@ -187,7 +193,7 @@ class CORE_EXPORT QgsSvgCache : public QObject

//! Get SVG content
QByteArray svgContent( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth,
double widthScaleFactor );
double widthScaleFactor, double fixedAspectRatio = 0);

signals:
//! Emit a signal to be caught by qgisapp and display a msg on status bar
Expand All @@ -204,14 +210,14 @@ class CORE_EXPORT QgsSvgCache : public QObject
* \param widthScaleFactor width scale factor
*/
QgsSvgCacheEntry *insertSvg( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth,
double widthScaleFactor );
double widthScaleFactor, double fixedAspectRatio = 0 );

void replaceParamsAndCacheSvg( QgsSvgCacheEntry *entry );
void cacheImage( QgsSvgCacheEntry *entry );
void cachePicture( QgsSvgCacheEntry *entry, bool forceVectorOutput = false );
//! Returns entry from cache or creates a new entry if it does not exist already
QgsSvgCacheEntry *cacheEntry( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth,
double widthScaleFactor );
double widthScaleFactor, double fixedAspectRatio = 0 );

//! Removes the least used items until the maximum size is under the limit
void trimToMaximumSize();
Expand Down

0 comments on commit 740ccbe

Please sign in to comment.