28#include <QApplication>
29#include <QCoreApplication>
31#include <QDomDocument>
36#include <QNetworkReply>
37#include <QNetworkRequest>
40#include <QRegularExpression>
41#include <QSvgRenderer>
43#include "moc_qgssvgcache.cpp"
51QgsSvgCacheEntry::QgsSvgCacheEntry(
const QString &path,
double size,
double strokeWidth,
double widthScaleFactor,
const QColor &fill,
const QColor &stroke,
double fixedAspectRatio,
const QMap<QString, QString> ¶meters )
54 , strokeWidth( strokeWidth )
55 , widthScaleFactor( widthScaleFactor )
56 , fixedAspectRatio( fixedAspectRatio )
59 , parameters( parameters )
65 const QgsSvgCacheEntry *otherSvg =
dynamic_cast< const QgsSvgCacheEntry *
>( other );
68 || !
qgsDoubleNear( otherSvg->fixedAspectRatio, fixedAspectRatio )
71 || !
qgsDoubleNear( otherSvg->widthScaleFactor, widthScaleFactor )
72 || otherSvg->fill != fill
73 || otherSvg->stroke != stroke
74 || otherSvg->path != path
75 || otherSvg->parameters != parameters )
81int QgsSvgCacheEntry::dataSize()
const
83 int size = svgContent.size();
86 size += picture->size();
90 size += ( image->width() * image->height() * 32 );
95void QgsSvgCacheEntry::dump()
const
97 QgsDebugMsgLevel( QStringLiteral(
"path: %1, size %2, width scale factor %3" ).arg( path ).arg( size ).arg( widthScaleFactor ), 4 );
109 mMissingSvg = QStringLiteral(
"<svg width='10' height='10'><text x='5' y='10' font-size='10' text-anchor='middle'>?</text></svg>" ).toLatin1();
112 if ( QFile::exists( downloadingSvgPath ) )
114 QFile file( downloadingSvgPath );
115 if ( file.open( QIODevice::ReadOnly ) )
117 mFetchingSvg = file.readAll();
121 if ( mFetchingSvg.isEmpty() )
123 mFetchingSvg = QStringLiteral(
"<svg width='10' height='10'><text x='5' y='10' font-size='10' text-anchor='middle'>?</text></svg>" ).toLatin1();
129QImage
QgsSvgCache::svgAsImage(
const QString &file,
double size,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
130 double widthScaleFactor,
bool &fitsInCache,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters )
132 const QMutexLocker locker( &
mMutex );
135 QgsSvgCacheEntry *currentEntry = cacheEntry( file, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking );
142 if ( !currentEntry->image )
144 const QSvgRenderer r( currentEntry->svgContent );
145 double hwRatio = 1.0;
146 if ( r.viewBoxF().width() > 0 )
148 if ( currentEntry->fixedAspectRatio > 0 )
150 hwRatio = currentEntry->fixedAspectRatio;
154 hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
157 long cachedDataSize = 0;
158 cachedDataSize += currentEntry->svgContent.size();
159 cachedDataSize +=
static_cast< int >( currentEntry->size * currentEntry->size * hwRatio * 32 );
163 currentEntry->image.reset();
166 if ( !currentEntry->picture )
168 cachePicture( currentEntry,
false );
172 result = imageFromCachedPicture( *currentEntry );
176 cacheImage( currentEntry );
177 result = *( currentEntry->image );
183 result = *( currentEntry->image );
190 double widthScaleFactor,
bool forceVectorOutput,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters )
192 const QMutexLocker locker( &
mMutex );
194 QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking );
198 if ( !currentEntry->picture )
200 cachePicture( currentEntry, forceVectorOutput );
209 p.setData( currentEntry->picture->data(), currentEntry->picture->size() );
213QByteArray
QgsSvgCache::svgContent(
const QString &path,
double size,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
214 double widthScaleFactor,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters,
bool *isMissingImage )
216 const QMutexLocker locker( &
mMutex );
218 QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking, isMissingImage );
220 return currentEntry->svgContent;
224 double widthScaleFactor,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters )
226 const QMutexLocker locker( &
mMutex );
228 QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking );
229 return currentEntry->viewboxSize;
232void QgsSvgCache::containsParams(
const QString &path,
bool &hasFillParam, QColor &defaultFillColor,
bool &hasStrokeParam, QColor &defaultStrokeColor,
233 bool &hasStrokeWidthParam,
double &defaultStrokeWidth,
bool blocking )
const
235 bool hasDefaultFillColor =
false;
236 bool hasFillOpacityParam =
false;
237 bool hasDefaultFillOpacity =
false;
238 double defaultFillOpacity = 1.0;
239 bool hasDefaultStrokeColor =
false;
240 bool hasDefaultStrokeWidth =
false;
241 bool hasStrokeOpacityParam =
false;
242 bool hasDefaultStrokeOpacity =
false;
243 double defaultStrokeOpacity = 1.0;
245 containsParams( path, hasFillParam, hasDefaultFillColor, defaultFillColor,
246 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
247 hasStrokeParam, hasDefaultStrokeColor, defaultStrokeColor,
248 hasStrokeWidthParam, hasDefaultStrokeWidth, defaultStrokeWidth,
249 hasStrokeOpacityParam, hasDefaultStrokeOpacity, defaultStrokeOpacity,
254 bool &hasFillParam,
bool &hasDefaultFillParam, QColor &defaultFillColor,
255 bool &hasFillOpacityParam,
bool &hasDefaultFillOpacity,
double &defaultFillOpacity,
256 bool &hasStrokeParam,
bool &hasDefaultStrokeColor, QColor &defaultStrokeColor,
257 bool &hasStrokeWidthParam,
bool &hasDefaultStrokeWidth,
double &defaultStrokeWidth,
258 bool &hasStrokeOpacityParam,
bool &hasDefaultStrokeOpacity,
double &defaultStrokeOpacity,
259 bool blocking )
const
261 hasFillParam =
false;
262 hasFillOpacityParam =
false;
263 hasStrokeParam =
false;
264 hasStrokeWidthParam =
false;
265 hasStrokeOpacityParam =
false;
266 defaultFillColor = QColor( Qt::white );
267 defaultFillOpacity = 1.0;
268 defaultStrokeColor = QColor( Qt::black );
269 defaultStrokeWidth = 0.2;
270 defaultStrokeOpacity = 1.0;
272 hasDefaultFillParam =
false;
273 hasDefaultFillOpacity =
false;
274 hasDefaultStrokeColor =
false;
275 hasDefaultStrokeWidth =
false;
276 hasDefaultStrokeOpacity =
false;
279 if ( !svgDoc.setContent(
getContent( path, mMissingSvg, mFetchingSvg, blocking ) ) )
284 const QDomElement docElem = svgDoc.documentElement();
285 containsElemParams( docElem, hasFillParam, hasDefaultFillParam, defaultFillColor,
286 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
287 hasStrokeParam, hasDefaultStrokeColor, defaultStrokeColor,
288 hasStrokeWidthParam, hasDefaultStrokeWidth, defaultStrokeWidth,
289 hasStrokeOpacityParam, hasDefaultStrokeOpacity, defaultStrokeOpacity );
292void QgsSvgCache::replaceParamsAndCacheSvg( QgsSvgCacheEntry *entry,
bool blocking )
299 const QByteArray content =
getContent( entry->path, mMissingSvg, mFetchingSvg, blocking ) ;
300 entry->isMissingImage = content == mMissingSvg;
302 if ( !svgDoc.setContent( content ) )
308 QDomElement docElem = svgDoc.documentElement();
311 const double sizeScaleFactor = calcSizeScaleFactor( entry, docElem, viewboxSize );
312 entry->viewboxSize = viewboxSize;
313 replaceElemParams( docElem, entry->fill, entry->stroke, entry->strokeWidth * sizeScaleFactor, entry->parameters );
315 entry->svgContent = svgDoc.toByteArray( 0 );
320 entry->svgContent.replace(
"\n<tspan",
"<tspan" );
321 entry->svgContent.replace(
"</tspan>\n",
"</tspan>" );
326double QgsSvgCache::calcSizeScaleFactor( QgsSvgCacheEntry *entry,
const QDomElement &docElem, QSizeF &viewboxSize )
const
336 if ( docElem.tagName() == QLatin1String(
"svg" ) && docElem.hasAttribute( QStringLiteral(
"viewBox" ) ) )
338 viewBox = docElem.attribute( QStringLiteral(
"viewBox" ), QString() );
340 else if ( docElem.tagName() == QLatin1String(
"svg" ) && docElem.hasAttribute( QStringLiteral(
"viewbox" ) ) )
342 viewBox = docElem.attribute( QStringLiteral(
"viewbox" ), QString() );
346 const QDomElement svgElem = docElem.firstChildElement( QStringLiteral(
"svg" ) );
347 if ( !svgElem.isNull() )
349 if ( svgElem.hasAttribute( QStringLiteral(
"viewBox" ) ) )
350 viewBox = svgElem.attribute( QStringLiteral(
"viewBox" ), QString() );
351 else if ( svgElem.hasAttribute( QStringLiteral(
"viewbox" ) ) )
352 viewBox = svgElem.attribute( QStringLiteral(
"viewbox" ), QString() );
357 if ( viewBox.isEmpty() )
360 if ( docElem.tagName() == QLatin1String(
"svg" ) && docElem.hasAttribute( QStringLiteral(
"width" ) ) )
362 const QString widthString = docElem.attribute( QStringLiteral(
"width" ) );
363 const thread_local QRegularExpression measureRegEx( QStringLiteral(
"([\\d\\.]+).*?$" ) );
364 const QRegularExpressionMatch widthMatch = measureRegEx.match( widthString );
365 if ( widthMatch.hasMatch() )
367 const double width = widthMatch.captured( 1 ).toDouble();
368 const QString heightString = docElem.attribute( QStringLiteral(
"height" ) );
370 const QRegularExpressionMatch heightMatch = measureRegEx.match( heightString );
371 if ( heightMatch.hasMatch() )
373 const double height = heightMatch.captured( 1 ).toDouble();
374 viewboxSize = QSizeF( width, height );
375 return width / entry->size;
385 const QStringList parts = viewBox.split(
' ' );
386 if ( parts.count() != 4 )
389 bool heightOk =
false;
390 const double height = parts.at( 3 ).toDouble( &heightOk );
392 bool widthOk =
false;
393 const double width = parts.at( 2 ).toDouble( &widthOk );
397 viewboxSize = QSizeF( width, height );
398 return width / entry->size;
407 return getContent( path, mMissingSvg, mFetchingSvg, blocking );
414 const QString contentType = reply->header( QNetworkRequest::ContentTypeHeader ).toString();
415 if ( !contentType.startsWith( QLatin1String(
"image/svg+xml" ), Qt::CaseInsensitive )
416 && !contentType.startsWith( QLatin1String(
"text/plain" ), Qt::CaseInsensitive ) )
424void QgsSvgCache::cacheImage( QgsSvgCacheEntry *entry )
431 entry->image.reset();
435 const QSize imageSize = sizeForImage( *entry, viewBoxSize, scaledSize );
438 auto image = std::make_unique< QImage >( imageSize, QImage::Format_ARGB32_Premultiplied );
441 const bool isFixedAR = entry->fixedAspectRatio > 0;
443 QPainter p( image.get() );
444 QSvgRenderer r( entry->svgContent );
445 if (
qgsDoubleNear( viewBoxSize.width(), viewBoxSize.height() ) )
451 QSizeF s( viewBoxSize );
452 s.scale( scaledSize.width(), scaledSize.height(), isFixedAR ? Qt::IgnoreAspectRatio : Qt::KeepAspectRatio );
453 const QRectF rect( ( imageSize.width() - s.width() ) / 2, ( imageSize.height() - s.height() ) / 2, s.width(), s.height() );
454 r.render( &p, rect );
457 mTotalSize += ( image->width() * image->height() * 32 );
458 entry->image = std::move( image );
461void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry,
bool forceVectorOutput )
463 Q_UNUSED( forceVectorOutput )
469 entry->picture.reset();
471 const bool isFixedAR = entry->fixedAspectRatio > 0;
474 auto picture = std::make_unique< QPicture >();
476 QSvgRenderer r( entry->svgContent );
477 double hwRatio = 1.0;
478 if ( r.viewBoxF().width() > 0 )
482 hwRatio = entry->fixedAspectRatio;
486 hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
490 const double wSize = entry->size;
491 const double hSize = wSize * hwRatio;
493 QSizeF s( r.viewBoxF().size() );
494 s.scale( wSize, hSize, isFixedAR ? Qt::IgnoreAspectRatio : Qt::KeepAspectRatio );
495 rect = QRectF( -s.width() / 2.0, -s.height() / 2.0, s.width(), s.height() );
497 QPainter p( picture.get() );
498 r.render( &p, rect );
499 entry->picture = std::move( picture );
503QgsSvgCacheEntry *QgsSvgCache::cacheEntry(
const QString &path,
double size,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
504 double widthScaleFactor,
double fixedAspectRatio,
const QMap<QString, QString> ¶meters,
bool blocking,
bool *isMissingImage )
506 QgsSvgCacheEntry *currentEntry =
findExistingEntry(
new QgsSvgCacheEntry( path, size, strokeWidth, widthScaleFactor, fill, stroke, fixedAspectRatio, parameters ) );
508 if ( currentEntry->svgContent.isEmpty() )
510 replaceParamsAndCacheSvg( currentEntry, blocking );
513 if ( isMissingImage )
514 *isMissingImage = currentEntry->isMissingImage;
520void QgsSvgCache::replaceElemParams( QDomElement &elem,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
const QMap<QString, QString> ¶meters )
528 const QDomNamedNodeMap attributes = elem.attributes();
529 const int nAttributes = attributes.count();
530 for (
int i = 0; i < nAttributes; ++i )
532 const QDomAttr attribute = attributes.item( i ).toAttr();
534 if ( attribute.name().compare( QLatin1String(
"style" ), Qt::CaseInsensitive ) == 0 )
537 QString newAttributeString;
539 const QStringList entryList = attribute.value().split(
';' );
540 QStringList::const_iterator entryIt = entryList.constBegin();
541 for ( ; entryIt != entryList.constEnd(); ++entryIt )
543 const QStringList keyValueSplit = entryIt->split(
':' );
544 if ( keyValueSplit.size() < 2 )
548 const QString key = keyValueSplit.at( 0 );
549 QString value = keyValueSplit.at( 1 );
550 QString newValue = value;
551 value = value.trimmed().toLower();
553 if ( value.startsWith( QLatin1String(
"param(fill)" ) ) )
555 newValue = fill.name();
557 else if ( value.startsWith( QLatin1String(
"param(fill-opacity)" ) ) )
559 newValue = QString::number( fill.alphaF() );
561 else if ( value.startsWith( QLatin1String(
"param(outline)" ) ) )
563 newValue = stroke.name();
565 else if ( value.startsWith( QLatin1String(
"param(outline-opacity)" ) ) )
567 newValue = QString::number( stroke.alphaF() );
569 else if ( value.startsWith( QLatin1String(
"param(outline-width)" ) ) )
571 newValue = QString::number( strokeWidth );
574 if ( entryIt != entryList.constBegin() )
576 newAttributeString.append(
';' );
578 newAttributeString.append( key +
':' + newValue );
580 elem.setAttribute( attribute.name(), newAttributeString );
584 const QString value = attribute.value().trimmed().toLower();
585 if ( value.startsWith( QLatin1String(
"param(fill)" ) ) )
587 elem.setAttribute( attribute.name(), fill.name() );
589 else if ( value.startsWith( QLatin1String(
"param(fill-opacity)" ) ) )
591 elem.setAttribute( attribute.name(), fill.alphaF() );
593 else if ( value.startsWith( QLatin1String(
"param(outline)" ) ) )
595 elem.setAttribute( attribute.name(), stroke.name() );
597 else if ( value.startsWith( QLatin1String(
"param(outline-opacity)" ) ) )
599 elem.setAttribute( attribute.name(), stroke.alphaF() );
601 else if ( value.startsWith( QLatin1String(
"param(outline-width)" ) ) )
603 elem.setAttribute( attribute.name(), QString::number( strokeWidth ) );
607 QMap<QString, QString>::const_iterator paramIt = parameters.constBegin();
608 for ( ; paramIt != parameters.constEnd(); ++paramIt )
610 if ( value.startsWith( QString( QLatin1String(
"param(%1)" ) ).arg( paramIt.key() ) ) )
612 elem.setAttribute( attribute.name(), paramIt.value() );
620 QDomNode child = elem.firstChild();
621 if ( child.isText() && child.nodeValue().startsWith(
"param(" ) )
623 QMap<QString, QString>::const_iterator paramIt = parameters.constBegin();
624 for ( ; paramIt != parameters.constEnd(); ++paramIt )
626 if ( child.toText().data().startsWith( QString( QLatin1String(
"param(%1)" ) ).arg( paramIt.key() ) ) )
628 child.setNodeValue( paramIt.value() );
634 const QDomNodeList childList = elem.childNodes();
635 const int nChildren = childList.count();
636 for (
int i = 0; i < nChildren; ++i )
638 QDomElement childElem = childList.at( i ).toElement();
639 replaceElemParams( childElem, fill, stroke, strokeWidth, parameters );
643void QgsSvgCache::containsElemParams(
const QDomElement &elem,
bool &hasFillParam,
bool &hasDefaultFill, QColor &defaultFill,
644 bool &hasFillOpacityParam,
bool &hasDefaultFillOpacity,
double &defaultFillOpacity,
645 bool &hasStrokeParam,
bool &hasDefaultStroke, QColor &defaultStroke,
646 bool &hasStrokeWidthParam,
bool &hasDefaultStrokeWidth,
double &defaultStrokeWidth,
647 bool &hasStrokeOpacityParam,
bool &hasDefaultStrokeOpacity,
double &defaultStrokeOpacity )
const
655 if ( hasFillParam && hasStrokeParam && hasStrokeWidthParam && hasFillOpacityParam && hasStrokeOpacityParam )
661 const QDomNamedNodeMap attributes = elem.attributes();
662 const int nAttributes = attributes.count();
664 QStringList valueSplit;
665 for (
int i = 0; i < nAttributes; ++i )
667 const QDomAttr attribute = attributes.item( i ).toAttr();
668 if ( attribute.name().compare( QLatin1String(
"style" ), Qt::CaseInsensitive ) == 0 )
671 const QStringList entryList = attribute.value().split(
';' );
672 QStringList::const_iterator entryIt = entryList.constBegin();
673 for ( ; entryIt != entryList.constEnd(); ++entryIt )
675 const QStringList keyValueSplit = entryIt->split(
':' );
676 if ( keyValueSplit.size() < 2 )
680 const QString value = keyValueSplit.at( 1 );
681 valueSplit = value.split(
' ' );
682 if ( !hasFillParam && value.startsWith( QLatin1String(
"param(fill)" ) ) )
685 if ( valueSplit.size() > 1 )
687 defaultFill = QColor( valueSplit.at( 1 ) );
688 hasDefaultFill =
true;
691 else if ( !hasFillOpacityParam && value.startsWith( QLatin1String(
"param(fill-opacity)" ) ) )
693 hasFillOpacityParam =
true;
694 if ( valueSplit.size() > 1 )
697 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
700 defaultFillOpacity = opacity;
701 hasDefaultFillOpacity =
true;
705 else if ( !hasStrokeParam && value.startsWith( QLatin1String(
"param(outline)" ) ) )
707 hasStrokeParam =
true;
708 if ( valueSplit.size() > 1 )
710 defaultStroke = QColor( valueSplit.at( 1 ) );
711 hasDefaultStroke =
true;
714 else if ( !hasStrokeWidthParam && value.startsWith( QLatin1String(
"param(outline-width)" ) ) )
716 hasStrokeWidthParam =
true;
717 if ( valueSplit.size() > 1 )
719 defaultStrokeWidth = valueSplit.at( 1 ).toDouble();
720 hasDefaultStrokeWidth =
true;
723 else if ( !hasStrokeOpacityParam && value.startsWith( QLatin1String(
"param(outline-opacity)" ) ) )
725 hasStrokeOpacityParam =
true;
726 if ( valueSplit.size() > 1 )
729 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
732 defaultStrokeOpacity = opacity;
733 hasDefaultStrokeOpacity =
true;
741 const QString value = attribute.value();
742 valueSplit = value.split(
' ' );
743 if ( !hasFillParam && value.startsWith( QLatin1String(
"param(fill)" ) ) )
746 if ( valueSplit.size() > 1 )
748 defaultFill = QColor( valueSplit.at( 1 ) );
749 hasDefaultFill =
true;
752 else if ( !hasFillOpacityParam && value.startsWith( QLatin1String(
"param(fill-opacity)" ) ) )
754 hasFillOpacityParam =
true;
755 if ( valueSplit.size() > 1 )
758 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
761 defaultFillOpacity = opacity;
762 hasDefaultFillOpacity =
true;
766 else if ( !hasStrokeParam && value.startsWith( QLatin1String(
"param(outline)" ) ) )
768 hasStrokeParam =
true;
769 if ( valueSplit.size() > 1 )
771 defaultStroke = QColor( valueSplit.at( 1 ) );
772 hasDefaultStroke =
true;
775 else if ( !hasStrokeWidthParam && value.startsWith( QLatin1String(
"param(outline-width)" ) ) )
777 hasStrokeWidthParam =
true;
778 if ( valueSplit.size() > 1 )
780 defaultStrokeWidth = valueSplit.at( 1 ).toDouble();
781 hasDefaultStrokeWidth =
true;
784 else if ( !hasStrokeOpacityParam && value.startsWith( QLatin1String(
"param(outline-opacity)" ) ) )
786 hasStrokeOpacityParam =
true;
787 if ( valueSplit.size() > 1 )
790 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
793 defaultStrokeOpacity = opacity;
794 hasDefaultStrokeOpacity =
true;
802 const QDomNodeList childList = elem.childNodes();
803 const int nChildren = childList.count();
804 for (
int i = 0; i < nChildren; ++i )
806 const QDomElement childElem = childList.at( i ).toElement();
807 containsElemParams( childElem, hasFillParam, hasDefaultFill, defaultFill,
808 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
809 hasStrokeParam, hasDefaultStroke, defaultStroke,
810 hasStrokeWidthParam, hasDefaultStrokeWidth, defaultStrokeWidth,
811 hasStrokeOpacityParam, hasDefaultStrokeOpacity, defaultStrokeOpacity );
815QSize QgsSvgCache::sizeForImage(
const QgsSvgCacheEntry &entry, QSizeF &viewBoxSize, QSizeF &scaledSize )
const
817 const bool isFixedAR = entry.fixedAspectRatio > 0;
819 const QSvgRenderer r( entry.svgContent );
820 double hwRatio = 1.0;
821 viewBoxSize = r.viewBoxF().size();
822 if ( viewBoxSize.width() > 0 )
826 hwRatio = entry.fixedAspectRatio;
830 hwRatio = viewBoxSize.height() / viewBoxSize.width();
835 scaledSize.setWidth( entry.size );
836 int wImgSize =
static_cast< int >( scaledSize.width() );
841 scaledSize.setHeight( scaledSize.width() * hwRatio );
842 int hImgSize =
static_cast< int >( scaledSize.height() );
847 return QSize( wImgSize, hImgSize );
850QImage QgsSvgCache::imageFromCachedPicture(
const QgsSvgCacheEntry &entry )
const
854 QImage image( sizeForImage( entry, viewBoxSize, scaledSize ), QImage::Format_ARGB32_Premultiplied );
857 QPainter p( &image );
858 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)