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(
const QString &path,
double size,
double strokeWidth,
double widthScaleFactor,
const QColor &fill,
const QColor &stroke,
double fixedAspectRatio,
const QMap<QString, QString> ¶meters )
57 , strokeWidth( strokeWidth )
58 , widthScaleFactor( widthScaleFactor )
59 , fixedAspectRatio( fixedAspectRatio )
62 , parameters( parameters )
68 const QgsSvgCacheEntry *otherSvg =
dynamic_cast< const QgsSvgCacheEntry *
>( other );
71 || !
qgsDoubleNear( otherSvg->fixedAspectRatio, fixedAspectRatio )
74 || !
qgsDoubleNear( otherSvg->widthScaleFactor, widthScaleFactor )
75 || otherSvg->fill != fill
76 || otherSvg->stroke != stroke
77 || otherSvg->path != path
78 || otherSvg->parameters != parameters )
84int QgsSvgCacheEntry::dataSize()
const
86 int size = svgContent.size();
89 size += picture->size();
93 size += ( image->width() * image->height() * 32 );
98void QgsSvgCacheEntry::dump()
const
100 QgsDebugMsgLevel( u
"path: %1, size %2, width scale factor %3"_s.arg( path ).arg( size ).arg( widthScaleFactor ), 4 );
112 mMissingSvg = u
"<svg width='10' height='10'><text x='5' y='10' font-size='10' text-anchor='middle'>?</text></svg>"_s.toLatin1();
115 if ( QFile::exists( downloadingSvgPath ) )
117 QFile file( downloadingSvgPath );
118 if ( file.open( QIODevice::ReadOnly ) )
120 mFetchingSvg = file.readAll();
124 if ( mFetchingSvg.isEmpty() )
126 mFetchingSvg = u
"<svg width='10' height='10'><text x='5' y='10' font-size='10' text-anchor='middle'>?</text></svg>"_s.toLatin1();
132QImage
QgsSvgCache::svgAsImage(
const QString &file,
double size,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
133 double widthScaleFactor,
bool &fitsInCache,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters )
135 const QMutexLocker locker( &
mMutex );
138 QgsSvgCacheEntry *currentEntry = cacheEntry( file, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking );
145 if ( !currentEntry->image )
147 const QSvgRenderer r( currentEntry->svgContent );
148 double hwRatio = 1.0;
149 if ( r.viewBoxF().width() > 0 )
151 if ( currentEntry->fixedAspectRatio > 0 )
153 hwRatio = currentEntry->fixedAspectRatio;
157 hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
160 long cachedDataSize = 0;
161 cachedDataSize += currentEntry->svgContent.size();
162 cachedDataSize +=
static_cast< int >( currentEntry->size * currentEntry->size * hwRatio * 32 );
166 currentEntry->image.reset();
169 if ( !currentEntry->picture )
171 cachePicture( currentEntry,
false );
175 result = imageFromCachedPicture( *currentEntry );
179 cacheImage( currentEntry );
180 result = *( currentEntry->image );
186 result = *( currentEntry->image );
193 double widthScaleFactor,
bool forceVectorOutput,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters )
195 const QMutexLocker locker( &
mMutex );
197 QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking );
201 if ( !currentEntry->picture )
203 cachePicture( currentEntry, forceVectorOutput );
212 p.setData( currentEntry->picture->data(), currentEntry->picture->size() );
216QByteArray
QgsSvgCache::svgContent(
const QString &path,
double size,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
217 double widthScaleFactor,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters,
bool *isMissingImage )
219 const QMutexLocker locker( &
mMutex );
221 QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking, isMissingImage );
223 return currentEntry->svgContent;
227 double widthScaleFactor,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters )
229 const QMutexLocker locker( &
mMutex );
231 QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking );
232 return currentEntry->viewboxSize;
235void QgsSvgCache::containsParams(
const QString &path,
bool &hasFillParam, QColor &defaultFillColor,
bool &hasStrokeParam, QColor &defaultStrokeColor,
236 bool &hasStrokeWidthParam,
double &defaultStrokeWidth,
bool blocking )
const
238 bool hasDefaultFillColor =
false;
239 bool hasFillOpacityParam =
false;
240 bool hasDefaultFillOpacity =
false;
241 double defaultFillOpacity = 1.0;
242 bool hasDefaultStrokeColor =
false;
243 bool hasDefaultStrokeWidth =
false;
244 bool hasStrokeOpacityParam =
false;
245 bool hasDefaultStrokeOpacity =
false;
246 double defaultStrokeOpacity = 1.0;
248 containsParams( path, hasFillParam, hasDefaultFillColor, defaultFillColor,
249 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
250 hasStrokeParam, hasDefaultStrokeColor, defaultStrokeColor,
251 hasStrokeWidthParam, hasDefaultStrokeWidth, defaultStrokeWidth,
252 hasStrokeOpacityParam, hasDefaultStrokeOpacity, defaultStrokeOpacity,
257 bool &hasFillParam,
bool &hasDefaultFillParam, QColor &defaultFillColor,
258 bool &hasFillOpacityParam,
bool &hasDefaultFillOpacity,
double &defaultFillOpacity,
259 bool &hasStrokeParam,
bool &hasDefaultStrokeColor, QColor &defaultStrokeColor,
260 bool &hasStrokeWidthParam,
bool &hasDefaultStrokeWidth,
double &defaultStrokeWidth,
261 bool &hasStrokeOpacityParam,
bool &hasDefaultStrokeOpacity,
double &defaultStrokeOpacity,
262 bool blocking )
const
264 hasFillParam =
false;
265 hasFillOpacityParam =
false;
266 hasStrokeParam =
false;
267 hasStrokeWidthParam =
false;
268 hasStrokeOpacityParam =
false;
269 defaultFillColor = QColor( Qt::white );
270 defaultFillOpacity = 1.0;
271 defaultStrokeColor = QColor( Qt::black );
272 defaultStrokeWidth = 0.2;
273 defaultStrokeOpacity = 1.0;
275 hasDefaultFillParam =
false;
276 hasDefaultFillOpacity =
false;
277 hasDefaultStrokeColor =
false;
278 hasDefaultStrokeWidth =
false;
279 hasDefaultStrokeOpacity =
false;
282 if ( !svgDoc.setContent(
getContent( path, mMissingSvg, mFetchingSvg, blocking ) ) )
287 const QDomElement docElem = svgDoc.documentElement();
288 containsElemParams( docElem, hasFillParam, hasDefaultFillParam, defaultFillColor,
289 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
290 hasStrokeParam, hasDefaultStrokeColor, defaultStrokeColor,
291 hasStrokeWidthParam, hasDefaultStrokeWidth, defaultStrokeWidth,
292 hasStrokeOpacityParam, hasDefaultStrokeOpacity, defaultStrokeOpacity );
295void QgsSvgCache::replaceParamsAndCacheSvg( QgsSvgCacheEntry *entry,
bool blocking )
302 const QByteArray content =
getContent( entry->path, mMissingSvg, mFetchingSvg, blocking ) ;
303 entry->isMissingImage = content == mMissingSvg;
305 if ( !svgDoc.setContent( content ) )
311 QDomElement docElem = svgDoc.documentElement();
314 const double sizeScaleFactor = calcSizeScaleFactor( entry, docElem, viewboxSize );
315 entry->viewboxSize = viewboxSize;
316 replaceElemParams( docElem, entry->fill, entry->stroke, entry->strokeWidth * sizeScaleFactor, entry->parameters );
318 entry->svgContent = svgDoc.toByteArray( 0 );
323 entry->svgContent.replace(
"\n<tspan",
"<tspan" );
324 entry->svgContent.replace(
"</tspan>\n",
"</tspan>" );
329double QgsSvgCache::calcSizeScaleFactor( QgsSvgCacheEntry *entry,
const QDomElement &docElem, QSizeF &viewboxSize )
const
339 if ( docElem.tagName() ==
"svg"_L1 && docElem.hasAttribute( u
"viewBox"_s ) )
341 viewBox = docElem.attribute( u
"viewBox"_s, QString() );
343 else if ( docElem.tagName() ==
"svg"_L1 && docElem.hasAttribute( u
"viewbox"_s ) )
345 viewBox = docElem.attribute( u
"viewbox"_s, QString() );
349 const QDomElement svgElem = docElem.firstChildElement( u
"svg"_s );
350 if ( !svgElem.isNull() )
352 if ( svgElem.hasAttribute( u
"viewBox"_s ) )
353 viewBox = svgElem.attribute( u
"viewBox"_s, QString() );
354 else if ( svgElem.hasAttribute( u
"viewbox"_s ) )
355 viewBox = svgElem.attribute( u
"viewbox"_s, QString() );
360 if ( viewBox.isEmpty() )
363 if ( docElem.tagName() ==
"svg"_L1 && docElem.hasAttribute( u
"width"_s ) )
365 const QString widthString = docElem.attribute( u
"width"_s );
366 const thread_local QRegularExpression measureRegEx( u
"([\\d\\.]+).*?$"_s );
367 const QRegularExpressionMatch widthMatch = measureRegEx.match( widthString );
368 if ( widthMatch.hasMatch() )
370 const double width = widthMatch.captured( 1 ).toDouble();
371 const QString heightString = docElem.attribute( u
"height"_s );
373 const QRegularExpressionMatch heightMatch = measureRegEx.match( heightString );
374 if ( heightMatch.hasMatch() )
376 const double height = heightMatch.captured( 1 ).toDouble();
377 viewboxSize = QSizeF( width, height );
378 return width / entry->size;
388 const QStringList parts = viewBox.split(
' ' );
389 if ( parts.count() != 4 )
392 bool heightOk =
false;
393 const double height = parts.at( 3 ).toDouble( &heightOk );
395 bool widthOk =
false;
396 const double width = parts.at( 2 ).toDouble( &widthOk );
400 viewboxSize = QSizeF( width, height );
401 return width / entry->size;
410 return getContent( path, mMissingSvg, mFetchingSvg, blocking );
417 const QString contentType = reply->header( QNetworkRequest::ContentTypeHeader ).toString();
418 if ( !contentType.startsWith(
"image/svg+xml"_L1, Qt::CaseInsensitive )
419 && !contentType.startsWith(
"text/plain"_L1, Qt::CaseInsensitive ) )
427void QgsSvgCache::cacheImage( QgsSvgCacheEntry *entry )
434 entry->image.reset();
438 const QSize imageSize = sizeForImage( *entry, viewBoxSize, scaledSize );
441 auto image = std::make_unique< QImage >( imageSize, QImage::Format_ARGB32_Premultiplied );
444 const bool isFixedAR = entry->fixedAspectRatio > 0;
446 QPainter p( image.get() );
447 QSvgRenderer r( entry->svgContent );
448 if (
qgsDoubleNear( viewBoxSize.width(), viewBoxSize.height() ) )
454 QSizeF s( viewBoxSize );
455 s.scale( scaledSize.width(), scaledSize.height(), isFixedAR ? Qt::IgnoreAspectRatio : Qt::KeepAspectRatio );
456 const QRectF rect( ( imageSize.width() - s.width() ) / 2, ( imageSize.height() - s.height() ) / 2, s.width(), s.height() );
457 r.render( &p, rect );
460 mTotalSize += ( image->width() * image->height() * 32 );
461 entry->image = std::move( image );
464void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry,
bool forceVectorOutput )
466 Q_UNUSED( forceVectorOutput )
472 entry->picture.reset();
474 const bool isFixedAR = entry->fixedAspectRatio > 0;
477 auto picture = std::make_unique< QPicture >();
479 QSvgRenderer r( entry->svgContent );
480 double hwRatio = 1.0;
481 if ( r.viewBoxF().width() > 0 )
485 hwRatio = entry->fixedAspectRatio;
489 hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
493 const double wSize = entry->size;
494 const double hSize = wSize * hwRatio;
496 QSizeF s( r.viewBoxF().size() );
497 s.scale( wSize, hSize, isFixedAR ? Qt::IgnoreAspectRatio : Qt::KeepAspectRatio );
498 rect = QRectF( -s.width() / 2.0, -s.height() / 2.0, s.width(), s.height() );
500 QPainter p( picture.get() );
501 r.render( &p, rect );
502 entry->picture = std::move( picture );
506QgsSvgCacheEntry *QgsSvgCache::cacheEntry(
const QString &path,
double size,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
507 double widthScaleFactor,
double fixedAspectRatio,
const QMap<QString, QString> ¶meters,
bool blocking,
bool *isMissingImage )
509 QgsSvgCacheEntry *currentEntry =
findExistingEntry(
new QgsSvgCacheEntry( path, size, strokeWidth, widthScaleFactor, fill, stroke, fixedAspectRatio, parameters ) );
511 if ( currentEntry->svgContent.isEmpty() )
513 replaceParamsAndCacheSvg( currentEntry, blocking );
516 if ( isMissingImage )
517 *isMissingImage = currentEntry->isMissingImage;
523void QgsSvgCache::replaceElemParams( QDomElement &elem,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
const QMap<QString, QString> ¶meters )
531 const QDomNamedNodeMap attributes = elem.attributes();
532 const int nAttributes = attributes.count();
533 for (
int i = 0; i < nAttributes; ++i )
535 const QDomAttr attribute = attributes.item( i ).toAttr();
537 if ( attribute.name().compare(
"style"_L1, Qt::CaseInsensitive ) == 0 )
540 QString newAttributeString;
542 const QStringList entryList = attribute.value().split(
';' );
543 QStringList::const_iterator entryIt = entryList.constBegin();
544 for ( ; entryIt != entryList.constEnd(); ++entryIt )
546 const QStringList keyValueSplit = entryIt->split(
':' );
547 if ( keyValueSplit.size() < 2 )
551 const QString key = keyValueSplit.at( 0 );
552 QString value = keyValueSplit.at( 1 );
553 QString newValue = value;
554 value = value.trimmed().toLower();
556 if ( value.startsWith(
"param(fill)"_L1 ) )
558 newValue = fill.name();
560 else if ( value.startsWith(
"param(fill-opacity)"_L1 ) )
562 newValue = QString::number( fill.alphaF() );
564 else if ( value.startsWith(
"param(outline)"_L1 ) )
566 newValue = stroke.name();
568 else if ( value.startsWith(
"param(outline-opacity)"_L1 ) )
570 newValue = QString::number( stroke.alphaF() );
572 else if ( value.startsWith(
"param(outline-width)"_L1 ) )
574 newValue = QString::number( strokeWidth );
577 if ( entryIt != entryList.constBegin() )
579 newAttributeString.append(
';' );
581 newAttributeString.append( key +
':' + newValue );
583 elem.setAttribute( attribute.name(), newAttributeString );
587 const QString value = attribute.value().trimmed().toLower();
588 if ( value.startsWith(
"param(fill)"_L1 ) )
590 elem.setAttribute( attribute.name(), fill.name() );
592 else if ( value.startsWith(
"param(fill-opacity)"_L1 ) )
594 elem.setAttribute( attribute.name(), fill.alphaF() );
596 else if ( value.startsWith(
"param(outline)"_L1 ) )
598 elem.setAttribute( attribute.name(), stroke.name() );
600 else if ( value.startsWith(
"param(outline-opacity)"_L1 ) )
602 elem.setAttribute( attribute.name(), stroke.alphaF() );
604 else if ( value.startsWith(
"param(outline-width)"_L1 ) )
606 elem.setAttribute( attribute.name(), QString::number( strokeWidth ) );
610 QMap<QString, QString>::const_iterator paramIt = parameters.constBegin();
611 for ( ; paramIt != parameters.constEnd(); ++paramIt )
613 if ( value.startsWith( QString(
"param(%1)"_L1 ).arg( paramIt.key() ) ) )
615 elem.setAttribute( attribute.name(), paramIt.value() );
623 QDomNode child = elem.firstChild();
624 if ( child.isText() && child.nodeValue().startsWith(
"param(" ) )
626 QMap<QString, QString>::const_iterator paramIt = parameters.constBegin();
627 for ( ; paramIt != parameters.constEnd(); ++paramIt )
629 if ( child.toText().data().startsWith( QString(
"param(%1)"_L1 ).arg( paramIt.key() ) ) )
631 child.setNodeValue( paramIt.value() );
637 const QDomNodeList childList = elem.childNodes();
638 const int nChildren = childList.count();
639 for (
int i = 0; i < nChildren; ++i )
641 QDomElement childElem = childList.at( i ).toElement();
642 replaceElemParams( childElem, fill, stroke, strokeWidth, parameters );
646void QgsSvgCache::containsElemParams(
const QDomElement &elem,
bool &hasFillParam,
bool &hasDefaultFill, QColor &defaultFill,
647 bool &hasFillOpacityParam,
bool &hasDefaultFillOpacity,
double &defaultFillOpacity,
648 bool &hasStrokeParam,
bool &hasDefaultStroke, QColor &defaultStroke,
649 bool &hasStrokeWidthParam,
bool &hasDefaultStrokeWidth,
double &defaultStrokeWidth,
650 bool &hasStrokeOpacityParam,
bool &hasDefaultStrokeOpacity,
double &defaultStrokeOpacity )
const
658 if ( hasFillParam && hasStrokeParam && hasStrokeWidthParam && hasFillOpacityParam && hasStrokeOpacityParam )
664 const QDomNamedNodeMap attributes = elem.attributes();
665 const int nAttributes = attributes.count();
667 QStringList valueSplit;
668 for (
int i = 0; i < nAttributes; ++i )
670 const QDomAttr attribute = attributes.item( i ).toAttr();
671 if ( attribute.name().compare(
"style"_L1, Qt::CaseInsensitive ) == 0 )
674 const QStringList entryList = attribute.value().split(
';' );
675 QStringList::const_iterator entryIt = entryList.constBegin();
676 for ( ; entryIt != entryList.constEnd(); ++entryIt )
678 const QStringList keyValueSplit = entryIt->split(
':' );
679 if ( keyValueSplit.size() < 2 )
683 const QString value = keyValueSplit.at( 1 );
684 valueSplit = value.split(
' ' );
685 if ( !hasFillParam && value.startsWith(
"param(fill)"_L1 ) )
688 if ( valueSplit.size() > 1 )
690 defaultFill = QColor( valueSplit.at( 1 ) );
691 hasDefaultFill =
true;
694 else if ( !hasFillOpacityParam && value.startsWith(
"param(fill-opacity)"_L1 ) )
696 hasFillOpacityParam =
true;
697 if ( valueSplit.size() > 1 )
700 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
703 defaultFillOpacity = opacity;
704 hasDefaultFillOpacity =
true;
708 else if ( !hasStrokeParam && value.startsWith(
"param(outline)"_L1 ) )
710 hasStrokeParam =
true;
711 if ( valueSplit.size() > 1 )
713 defaultStroke = QColor( valueSplit.at( 1 ) );
714 hasDefaultStroke =
true;
717 else if ( !hasStrokeWidthParam && value.startsWith(
"param(outline-width)"_L1 ) )
719 hasStrokeWidthParam =
true;
720 if ( valueSplit.size() > 1 )
722 defaultStrokeWidth = valueSplit.at( 1 ).toDouble();
723 hasDefaultStrokeWidth =
true;
726 else if ( !hasStrokeOpacityParam && value.startsWith(
"param(outline-opacity)"_L1 ) )
728 hasStrokeOpacityParam =
true;
729 if ( valueSplit.size() > 1 )
732 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
735 defaultStrokeOpacity = opacity;
736 hasDefaultStrokeOpacity =
true;
744 const QString value = attribute.value();
745 valueSplit = value.split(
' ' );
746 if ( !hasFillParam && value.startsWith(
"param(fill)"_L1 ) )
749 if ( valueSplit.size() > 1 )
751 defaultFill = QColor( valueSplit.at( 1 ) );
752 hasDefaultFill =
true;
755 else if ( !hasFillOpacityParam && value.startsWith(
"param(fill-opacity)"_L1 ) )
757 hasFillOpacityParam =
true;
758 if ( valueSplit.size() > 1 )
761 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
764 defaultFillOpacity = opacity;
765 hasDefaultFillOpacity =
true;
769 else if ( !hasStrokeParam && value.startsWith(
"param(outline)"_L1 ) )
771 hasStrokeParam =
true;
772 if ( valueSplit.size() > 1 )
774 defaultStroke = QColor( valueSplit.at( 1 ) );
775 hasDefaultStroke =
true;
778 else if ( !hasStrokeWidthParam && value.startsWith(
"param(outline-width)"_L1 ) )
780 hasStrokeWidthParam =
true;
781 if ( valueSplit.size() > 1 )
783 defaultStrokeWidth = valueSplit.at( 1 ).toDouble();
784 hasDefaultStrokeWidth =
true;
787 else if ( !hasStrokeOpacityParam && value.startsWith(
"param(outline-opacity)"_L1 ) )
789 hasStrokeOpacityParam =
true;
790 if ( valueSplit.size() > 1 )
793 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
796 defaultStrokeOpacity = opacity;
797 hasDefaultStrokeOpacity =
true;
805 const QDomNodeList childList = elem.childNodes();
806 const int nChildren = childList.count();
807 for (
int i = 0; i < nChildren; ++i )
809 const QDomElement childElem = childList.at( i ).toElement();
810 containsElemParams( childElem, hasFillParam, hasDefaultFill, defaultFill,
811 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
812 hasStrokeParam, hasDefaultStroke, defaultStroke,
813 hasStrokeWidthParam, hasDefaultStrokeWidth, defaultStrokeWidth,
814 hasStrokeOpacityParam, hasDefaultStrokeOpacity, defaultStrokeOpacity );
818QSize QgsSvgCache::sizeForImage(
const QgsSvgCacheEntry &entry, QSizeF &viewBoxSize, QSizeF &scaledSize )
const
820 const bool isFixedAR = entry.fixedAspectRatio > 0;
822 const QSvgRenderer r( entry.svgContent );
823 double hwRatio = 1.0;
824 viewBoxSize = r.viewBoxF().size();
825 if ( viewBoxSize.width() > 0 )
829 hwRatio = entry.fixedAspectRatio;
833 hwRatio = viewBoxSize.height() / viewBoxSize.width();
838 scaledSize.setWidth( entry.size );
839 int wImgSize =
static_cast< int >( scaledSize.width() );
844 scaledSize.setHeight( scaledSize.width() * hwRatio );
845 int hImgSize =
static_cast< int >( scaledSize.height() );
850 return QSize( wImgSize, hImgSize );
853QImage QgsSvgCache::imageFromCachedPicture(
const QgsSvgCacheEntry &entry )
const
857 QImage image( sizeForImage( entry, viewBoxSize, scaledSize ), QImage::Format_ARGB32_Premultiplied );
860 QPainter p( &image );
861 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())
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)