28#include <QApplication>
29#include <QCoreApplication>
31#include <QDomDocument>
36#include <QNetworkReply>
37#include <QNetworkRequest>
40#include <QRegularExpression>
42#include <QSvgRenderer>
44#include "moc_qgssvgcache.cpp"
46using namespace Qt::StringLiterals;
54QgsSvgCacheEntry::QgsSvgCacheEntry(
55 const QString &path,
double size,
double strokeWidth,
double widthScaleFactor,
const QColor &fill,
const QColor &stroke,
double fixedAspectRatio,
const QMap<QString, QString> ¶meters
59 , strokeWidth( strokeWidth )
60 , widthScaleFactor( widthScaleFactor )
61 , fixedAspectRatio( fixedAspectRatio )
64 , parameters( parameters )
69 const QgsSvgCacheEntry *otherSvg =
dynamic_cast< const QgsSvgCacheEntry *
>( other );
72 || !
qgsDoubleNear( otherSvg->fixedAspectRatio, fixedAspectRatio )
75 || !
qgsDoubleNear( otherSvg->widthScaleFactor, widthScaleFactor )
76 || otherSvg->fill != fill
77 || otherSvg->stroke != stroke
78 || otherSvg->path != path
79 || otherSvg->parameters != parameters )
85int QgsSvgCacheEntry::dataSize()
const
87 int size = svgContent.size();
90 size += picture->size();
94 size += ( image->width() * image->height() * 32 );
99void QgsSvgCacheEntry::dump()
const
101 QgsDebugMsgLevel( u
"path: %1, size %2, width scale factor %3"_s.arg( path ).arg( size ).arg( widthScaleFactor ), 4 );
113 mMissingSvg = u
"<svg width='10' height='10'><text x='5' y='10' font-size='10' text-anchor='middle'>?</text></svg>"_s.toLatin1();
116 if ( QFile::exists( downloadingSvgPath ) )
118 QFile file( downloadingSvgPath );
119 if ( file.open( QIODevice::ReadOnly ) )
121 mFetchingSvg = file.readAll();
125 if ( mFetchingSvg.isEmpty() )
127 mFetchingSvg = u
"<svg width='10' height='10'><text x='5' y='10' font-size='10' text-anchor='middle'>?</text></svg>"_s.toLatin1();
137 const QColor &stroke,
139 double widthScaleFactor,
141 double fixedAspectRatio,
143 const QMap<QString, QString> ¶meters
146 const QMutexLocker locker( &
mMutex );
149 QgsSvgCacheEntry *currentEntry = cacheEntry( file, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking );
156 if ( !currentEntry->image )
158 const QSvgRenderer r( currentEntry->svgContent );
159 double hwRatio = 1.0;
160 if ( r.viewBoxF().width() > 0 )
162 if ( currentEntry->fixedAspectRatio > 0 )
164 hwRatio = currentEntry->fixedAspectRatio;
168 hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
171 long cachedDataSize = 0;
172 cachedDataSize += currentEntry->svgContent.size();
173 cachedDataSize +=
static_cast< int >( currentEntry->size * currentEntry->size * hwRatio * 32 );
177 currentEntry->image.reset();
180 if ( !currentEntry->picture )
182 cachePicture( currentEntry,
false );
186 result = imageFromCachedPicture( *currentEntry );
190 cacheImage( currentEntry );
191 result = *( currentEntry->image );
197 result = *( currentEntry->image );
207 const QColor &stroke,
209 double widthScaleFactor,
210 bool forceVectorOutput,
211 double fixedAspectRatio,
213 const QMap<QString, QString> ¶meters
216 const QMutexLocker locker( &
mMutex );
218 QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking );
222 if ( !currentEntry->picture )
224 cachePicture( currentEntry, forceVectorOutput );
233 p.setData( currentEntry->picture->data(), currentEntry->picture->size() );
241 const QColor &stroke,
243 double widthScaleFactor,
244 double fixedAspectRatio,
246 const QMap<QString, QString> ¶meters,
250 const QMutexLocker locker( &
mMutex );
252 QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking, isMissingImage );
254 return currentEntry->svgContent;
258 const QString &path,
double size,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
double widthScaleFactor,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters
261 const QMutexLocker locker( &
mMutex );
263 QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking );
264 return currentEntry->viewboxSize;
268 const QString &path,
bool &hasFillParam, QColor &defaultFillColor,
bool &hasStrokeParam, QColor &defaultStrokeColor,
bool &hasStrokeWidthParam,
double &defaultStrokeWidth,
bool blocking
271 bool hasDefaultFillColor =
false;
272 bool hasFillOpacityParam =
false;
273 bool hasDefaultFillOpacity =
false;
274 double defaultFillOpacity = 1.0;
275 bool hasDefaultStrokeColor =
false;
276 bool hasDefaultStrokeWidth =
false;
277 bool hasStrokeOpacityParam =
false;
278 bool hasDefaultStrokeOpacity =
false;
279 double defaultStrokeOpacity = 1.0;
287 hasDefaultFillOpacity,
290 hasDefaultStrokeColor,
293 hasDefaultStrokeWidth,
295 hasStrokeOpacityParam,
296 hasDefaultStrokeOpacity,
297 defaultStrokeOpacity,
305 bool &hasDefaultFillParam,
306 QColor &defaultFillColor,
307 bool &hasFillOpacityParam,
308 bool &hasDefaultFillOpacity,
309 double &defaultFillOpacity,
310 bool &hasStrokeParam,
311 bool &hasDefaultStrokeColor,
312 QColor &defaultStrokeColor,
313 bool &hasStrokeWidthParam,
314 bool &hasDefaultStrokeWidth,
315 double &defaultStrokeWidth,
316 bool &hasStrokeOpacityParam,
317 bool &hasDefaultStrokeOpacity,
318 double &defaultStrokeOpacity,
322 hasFillParam =
false;
323 hasFillOpacityParam =
false;
324 hasStrokeParam =
false;
325 hasStrokeWidthParam =
false;
326 hasStrokeOpacityParam =
false;
327 defaultFillColor = QColor( Qt::white );
328 defaultFillOpacity = 1.0;
329 defaultStrokeColor = QColor( Qt::black );
330 defaultStrokeWidth = 0.2;
331 defaultStrokeOpacity = 1.0;
333 hasDefaultFillParam =
false;
334 hasDefaultFillOpacity =
false;
335 hasDefaultStrokeColor =
false;
336 hasDefaultStrokeWidth =
false;
337 hasDefaultStrokeOpacity =
false;
340 if ( !svgDoc.setContent(
getContent( path, mMissingSvg, mFetchingSvg, blocking ) ) )
345 const QDomElement docElem = svgDoc.documentElement();
352 hasDefaultFillOpacity,
355 hasDefaultStrokeColor,
358 hasDefaultStrokeWidth,
360 hasStrokeOpacityParam,
361 hasDefaultStrokeOpacity,
366void QgsSvgCache::replaceParamsAndCacheSvg( QgsSvgCacheEntry *entry,
bool blocking )
373 const QByteArray content =
getContent( entry->path, mMissingSvg, mFetchingSvg, blocking );
374 entry->isMissingImage = content == mMissingSvg;
376 if ( !svgDoc.setContent( content ) )
382 QDomElement docElem = svgDoc.documentElement();
385 const double sizeScaleFactor = calcSizeScaleFactor( entry, docElem, viewboxSize );
386 entry->viewboxSize = viewboxSize;
387 replaceElemParams( docElem, entry->fill, entry->stroke, entry->strokeWidth * sizeScaleFactor, entry->parameters );
389 entry->svgContent = svgDoc.toByteArray( 0 );
394 entry->svgContent.replace(
"\n<tspan",
"<tspan" );
395 entry->svgContent.replace(
"</tspan>\n",
"</tspan>" );
400double QgsSvgCache::calcSizeScaleFactor( QgsSvgCacheEntry *entry,
const QDomElement &docElem, QSizeF &viewboxSize )
const
410 if ( docElem.tagName() ==
"svg"_L1 && docElem.hasAttribute( u
"viewBox"_s ) )
412 viewBox = docElem.attribute( u
"viewBox"_s, QString() );
414 else if ( docElem.tagName() ==
"svg"_L1 && docElem.hasAttribute( u
"viewbox"_s ) )
416 viewBox = docElem.attribute( u
"viewbox"_s, QString() );
420 const QDomElement svgElem = docElem.firstChildElement( u
"svg"_s );
421 if ( !svgElem.isNull() )
423 if ( svgElem.hasAttribute( u
"viewBox"_s ) )
424 viewBox = svgElem.attribute( u
"viewBox"_s, QString() );
425 else if ( svgElem.hasAttribute( u
"viewbox"_s ) )
426 viewBox = svgElem.attribute( u
"viewbox"_s, QString() );
431 if ( viewBox.isEmpty() )
434 if ( docElem.tagName() ==
"svg"_L1 && docElem.hasAttribute( u
"width"_s ) )
436 const QString widthString = docElem.attribute( u
"width"_s );
437 const thread_local QRegularExpression measureRegEx( u
"([\\d\\.]+).*?$"_s );
438 const QRegularExpressionMatch widthMatch = measureRegEx.match( widthString );
439 if ( widthMatch.hasMatch() )
441 const double width = widthMatch.captured( 1 ).toDouble();
442 const QString heightString = docElem.attribute( u
"height"_s );
444 const QRegularExpressionMatch heightMatch = measureRegEx.match( heightString );
445 if ( heightMatch.hasMatch() )
447 const double height = heightMatch.captured( 1 ).toDouble();
448 viewboxSize = QSizeF( width, height );
449 return width / entry->size;
459 const QStringList parts = viewBox.split(
' ' );
460 if ( parts.count() != 4 )
463 bool heightOk =
false;
464 const double height = parts.at( 3 ).toDouble( &heightOk );
466 bool widthOk =
false;
467 const double width = parts.at( 2 ).toDouble( &widthOk );
471 viewboxSize = QSizeF( width, height );
472 return width / entry->size;
481 return getContent( path, mMissingSvg, mFetchingSvg, blocking );
488 const QString contentType = reply->header( QNetworkRequest::ContentTypeHeader ).toString();
489 if ( !contentType.startsWith(
"image/svg+xml"_L1, Qt::CaseInsensitive ) && !contentType.startsWith(
"text/plain"_L1, Qt::CaseInsensitive ) )
497void QgsSvgCache::cacheImage( QgsSvgCacheEntry *entry )
504 entry->image.reset();
508 const QSize imageSize = sizeForImage( *entry, viewBoxSize, scaledSize );
511 auto image = std::make_unique< QImage >( imageSize, QImage::Format_ARGB32_Premultiplied );
514 const bool isFixedAR = entry->fixedAspectRatio > 0;
516 QPainter p( image.get() );
517 QSvgRenderer r( entry->svgContent );
518 if (
qgsDoubleNear( viewBoxSize.width(), viewBoxSize.height() ) )
524 QSizeF s( viewBoxSize );
525 s.scale( scaledSize.width(), scaledSize.height(), isFixedAR ? Qt::IgnoreAspectRatio : Qt::KeepAspectRatio );
526 const QRectF rect( ( imageSize.width() - s.width() ) / 2, ( imageSize.height() - s.height() ) / 2, s.width(), s.height() );
527 r.render( &p, rect );
530 mTotalSize += ( image->width() * image->height() * 32 );
531 entry->image = std::move( image );
534void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry,
bool forceVectorOutput )
536 Q_UNUSED( forceVectorOutput )
542 entry->picture.reset();
544 const bool isFixedAR = entry->fixedAspectRatio > 0;
547 auto picture = std::make_unique< QPicture >();
549 QSvgRenderer r( entry->svgContent );
550 double hwRatio = 1.0;
551 if ( r.viewBoxF().width() > 0 )
555 hwRatio = entry->fixedAspectRatio;
559 hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
563 const double wSize = entry->size;
564 const double hSize = wSize * hwRatio;
566 QSizeF s( r.viewBoxF().size() );
567 s.scale( wSize, hSize, isFixedAR ? Qt::IgnoreAspectRatio : Qt::KeepAspectRatio );
568 rect = QRectF( -s.width() / 2.0, -s.height() / 2.0, s.width(), s.height() );
570 QPainter p( picture.get() );
571 r.render( &p, rect );
572 entry->picture = std::move( picture );
576QgsSvgCacheEntry *QgsSvgCache::cacheEntry(
580 const QColor &stroke,
582 double widthScaleFactor,
583 double fixedAspectRatio,
584 const QMap<QString, QString> ¶meters,
589 QgsSvgCacheEntry *currentEntry =
findExistingEntry(
new QgsSvgCacheEntry( path, size, strokeWidth, widthScaleFactor, fill, stroke, fixedAspectRatio, parameters ) );
591 if ( currentEntry->svgContent.isEmpty() )
593 replaceParamsAndCacheSvg( currentEntry, blocking );
596 if ( isMissingImage )
597 *isMissingImage = currentEntry->isMissingImage;
603void QgsSvgCache::replaceElemParams( QDomElement &elem,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
const QMap<QString, QString> ¶meters )
611 const QDomNamedNodeMap attributes = elem.attributes();
612 const int nAttributes = attributes.count();
613 for (
int i = 0; i < nAttributes; ++i )
615 const QDomAttr attribute = attributes.item( i ).toAttr();
617 if ( attribute.name().compare(
"style"_L1, Qt::CaseInsensitive ) == 0 )
620 QString newAttributeString;
622 const QStringList entryList = attribute.value().split(
';' );
623 QStringList::const_iterator entryIt = entryList.constBegin();
624 for ( ; entryIt != entryList.constEnd(); ++entryIt )
626 const QStringList keyValueSplit = entryIt->split(
':' );
627 if ( keyValueSplit.size() < 2 )
631 const QString key = keyValueSplit.at( 0 );
632 QString value = keyValueSplit.at( 1 );
633 QString newValue = value;
634 value = value.trimmed().toLower();
636 if ( value.startsWith(
"param(fill)"_L1 ) )
638 newValue = fill.name();
640 else if ( value.startsWith(
"param(fill-opacity)"_L1 ) )
642 newValue = QString::number( fill.alphaF() );
644 else if ( value.startsWith(
"param(outline)"_L1 ) )
646 newValue = stroke.name();
648 else if ( value.startsWith(
"param(outline-opacity)"_L1 ) )
650 newValue = QString::number( stroke.alphaF() );
652 else if ( value.startsWith(
"param(outline-width)"_L1 ) )
654 newValue = QString::number( strokeWidth );
657 if ( entryIt != entryList.constBegin() )
659 newAttributeString.append(
';' );
661 newAttributeString.append( key +
':' + newValue );
663 elem.setAttribute( attribute.name(), newAttributeString );
667 const QString value = attribute.value().trimmed().toLower();
668 if ( value.startsWith(
"param(fill)"_L1 ) )
670 elem.setAttribute( attribute.name(), fill.name() );
672 else if ( value.startsWith(
"param(fill-opacity)"_L1 ) )
674 elem.setAttribute( attribute.name(), fill.alphaF() );
676 else if ( value.startsWith(
"param(outline)"_L1 ) )
678 elem.setAttribute( attribute.name(), stroke.name() );
680 else if ( value.startsWith(
"param(outline-opacity)"_L1 ) )
682 elem.setAttribute( attribute.name(), stroke.alphaF() );
684 else if ( value.startsWith(
"param(outline-width)"_L1 ) )
686 elem.setAttribute( attribute.name(), QString::number( strokeWidth ) );
690 QMap<QString, QString>::const_iterator paramIt = parameters.constBegin();
691 for ( ; paramIt != parameters.constEnd(); ++paramIt )
693 if ( value.startsWith( QString(
"param(%1)"_L1 ).arg( paramIt.key() ) ) )
695 elem.setAttribute( attribute.name(), paramIt.value() );
703 QDomNode child = elem.firstChild();
704 if ( child.isText() && child.nodeValue().startsWith(
"param(" ) )
706 QMap<QString, QString>::const_iterator paramIt = parameters.constBegin();
707 for ( ; paramIt != parameters.constEnd(); ++paramIt )
709 if ( child.toText().data().startsWith( QString(
"param(%1)"_L1 ).arg( paramIt.key() ) ) )
711 child.setNodeValue( paramIt.value() );
717 const QDomNodeList childList = elem.childNodes();
718 const int nChildren = childList.count();
719 for (
int i = 0; i < nChildren; ++i )
721 QDomElement childElem = childList.at( i ).toElement();
722 replaceElemParams( childElem, fill, stroke, strokeWidth, parameters );
726void QgsSvgCache::containsElemParams(
727 const QDomElement &elem,
729 bool &hasDefaultFill,
731 bool &hasFillOpacityParam,
732 bool &hasDefaultFillOpacity,
733 double &defaultFillOpacity,
734 bool &hasStrokeParam,
735 bool &hasDefaultStroke,
736 QColor &defaultStroke,
737 bool &hasStrokeWidthParam,
738 bool &hasDefaultStrokeWidth,
739 double &defaultStrokeWidth,
740 bool &hasStrokeOpacityParam,
741 bool &hasDefaultStrokeOpacity,
742 double &defaultStrokeOpacity
751 if ( hasFillParam && hasStrokeParam && hasStrokeWidthParam && hasFillOpacityParam && hasStrokeOpacityParam )
757 const QDomNamedNodeMap attributes = elem.attributes();
758 const int nAttributes = attributes.count();
760 QStringList valueSplit;
761 for (
int i = 0; i < nAttributes; ++i )
763 const QDomAttr attribute = attributes.item( i ).toAttr();
764 if ( attribute.name().compare(
"style"_L1, Qt::CaseInsensitive ) == 0 )
767 const QStringList entryList = attribute.value().split(
';' );
768 QStringList::const_iterator entryIt = entryList.constBegin();
769 for ( ; entryIt != entryList.constEnd(); ++entryIt )
771 const QStringList keyValueSplit = entryIt->split(
':' );
772 if ( keyValueSplit.size() < 2 )
776 const QString value = keyValueSplit.at( 1 );
777 valueSplit = value.split(
' ' );
778 if ( !hasFillParam && value.startsWith(
"param(fill)"_L1 ) )
781 if ( valueSplit.size() > 1 )
783 defaultFill = QColor( valueSplit.at( 1 ) );
784 hasDefaultFill =
true;
787 else if ( !hasFillOpacityParam && value.startsWith(
"param(fill-opacity)"_L1 ) )
789 hasFillOpacityParam =
true;
790 if ( valueSplit.size() > 1 )
793 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
796 defaultFillOpacity = opacity;
797 hasDefaultFillOpacity =
true;
801 else if ( !hasStrokeParam && value.startsWith(
"param(outline)"_L1 ) )
803 hasStrokeParam =
true;
804 if ( valueSplit.size() > 1 )
806 defaultStroke = QColor( valueSplit.at( 1 ) );
807 hasDefaultStroke =
true;
810 else if ( !hasStrokeWidthParam && value.startsWith(
"param(outline-width)"_L1 ) )
812 hasStrokeWidthParam =
true;
813 if ( valueSplit.size() > 1 )
815 defaultStrokeWidth = valueSplit.at( 1 ).toDouble();
816 hasDefaultStrokeWidth =
true;
819 else if ( !hasStrokeOpacityParam && value.startsWith(
"param(outline-opacity)"_L1 ) )
821 hasStrokeOpacityParam =
true;
822 if ( valueSplit.size() > 1 )
825 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
828 defaultStrokeOpacity = opacity;
829 hasDefaultStrokeOpacity =
true;
837 const QString value = attribute.value();
838 valueSplit = value.split(
' ' );
839 if ( !hasFillParam && value.startsWith(
"param(fill)"_L1 ) )
842 if ( valueSplit.size() > 1 )
844 defaultFill = QColor( valueSplit.at( 1 ) );
845 hasDefaultFill =
true;
848 else if ( !hasFillOpacityParam && value.startsWith(
"param(fill-opacity)"_L1 ) )
850 hasFillOpacityParam =
true;
851 if ( valueSplit.size() > 1 )
854 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
857 defaultFillOpacity = opacity;
858 hasDefaultFillOpacity =
true;
862 else if ( !hasStrokeParam && value.startsWith(
"param(outline)"_L1 ) )
864 hasStrokeParam =
true;
865 if ( valueSplit.size() > 1 )
867 defaultStroke = QColor( valueSplit.at( 1 ) );
868 hasDefaultStroke =
true;
871 else if ( !hasStrokeWidthParam && value.startsWith(
"param(outline-width)"_L1 ) )
873 hasStrokeWidthParam =
true;
874 if ( valueSplit.size() > 1 )
876 defaultStrokeWidth = valueSplit.at( 1 ).toDouble();
877 hasDefaultStrokeWidth =
true;
880 else if ( !hasStrokeOpacityParam && value.startsWith(
"param(outline-opacity)"_L1 ) )
882 hasStrokeOpacityParam =
true;
883 if ( valueSplit.size() > 1 )
886 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
889 defaultStrokeOpacity = opacity;
890 hasDefaultStrokeOpacity =
true;
898 const QDomNodeList childList = elem.childNodes();
899 const int nChildren = childList.count();
900 for (
int i = 0; i < nChildren; ++i )
902 const QDomElement childElem = childList.at( i ).toElement();
909 hasDefaultFillOpacity,
915 hasDefaultStrokeWidth,
917 hasStrokeOpacityParam,
918 hasDefaultStrokeOpacity,
924QSize QgsSvgCache::sizeForImage(
const QgsSvgCacheEntry &entry, QSizeF &viewBoxSize, QSizeF &scaledSize )
const
926 const bool isFixedAR = entry.fixedAspectRatio > 0;
928 const QSvgRenderer r( entry.svgContent );
929 double hwRatio = 1.0;
930 viewBoxSize = r.viewBoxF().size();
931 if ( viewBoxSize.width() > 0 )
935 hwRatio = entry.fixedAspectRatio;
939 hwRatio = viewBoxSize.height() / viewBoxSize.width();
944 scaledSize.setWidth( entry.size );
945 int wImgSize =
static_cast< int >( scaledSize.width() );
950 scaledSize.setHeight( scaledSize.width() * hwRatio );
951 int hImgSize =
static_cast< int >( scaledSize.height() );
956 return QSize( wImgSize, hImgSize );
959QImage QgsSvgCache::imageFromCachedPicture(
const QgsSvgCacheEntry &entry )
const
963 QImage image( sizeForImage( entry, viewBoxSize, scaledSize ), QImage::Format_ARGB32_Premultiplied );
966 QPainter p( &image );
967 p.drawPicture( QPoint( 0, 0 ), *entry.picture );
void remoteContentFetched(const QString &url)
Emitted when the cache has finished retrieving content from a remote url.
Base class for entries in a QgsAbstractContentCache.
Abstract base class for file content caches, such as SVG or raster image caches.
QByteArray getContent(const QString &path, const QByteArray &missingContent, const QByteArray &fetchingContent, bool blocking=false) const
QgsSvgCacheEntry * findExistingEntry(QgsSvgCacheEntry *entryTemplate)
QgsAbstractContentCache(QObject *parent=nullptr, const QString &typeString=QString(), long maxCacheSize=20000000, int fileModifiedCheckTimeout=30000)
static QString defaultThemePath()
Returns the path to the default theme directory.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
QSizeF svgViewboxSize(const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor, double fixedAspectRatio=0, bool blocking=false, const QMap< QString, QString > ¶meters=QMap< QString, QString >())
Calculates the viewbox size of a (possibly cached) SVG file.
QByteArray getImageData(const QString &path, bool blocking=false) const
Gets the SVG content corresponding to the given path.
QPicture svgAsPicture(const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor, bool forceVectorOutput=false, double fixedAspectRatio=0, bool blocking=false, const QMap< QString, QString > ¶meters=QMap< QString, QString >())
Returns an SVG drawing as a QPicture.
QgsSvgCache(QObject *parent=nullptr)
Constructor for QgsSvgCache.
bool checkReply(QNetworkReply *reply, const QString &path) const override
Runs additional checks on a network reply to ensure that the reply content is consistent with that re...
void containsParams(const QString &path, bool &hasFillParam, QColor &defaultFillColor, bool &hasStrokeParam, QColor &defaultStrokeColor, bool &hasStrokeWidthParam, double &defaultStrokeWidth, bool blocking=false) const
Tests if an SVG file contains parameters for fill, stroke color, stroke width.
void remoteSvgFetched(const QString &url)
Emitted when the cache has finished retrieving an SVG file from a remote url.
QImage svgAsImage(const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor, bool &fitsInCache, double fixedAspectRatio=0, bool blocking=false, const QMap< QString, QString > ¶meters=QMap< QString, QString >())
Returns an SVG drawing as a QImage.
QByteArray svgContent(const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor, double fixedAspectRatio=0, bool blocking=false, const QMap< QString, QString > ¶meters=QMap< QString, QString >(), bool *isMissingImage=nullptr)
Gets the SVG content corresponding to the given path.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
#define QgsDebugMsgLevel(str, level)