27#include <QApplication>
28#include <QCoreApplication>
30#include <QDomDocument>
36#include <QRegularExpression>
37#include <QSvgRenderer>
39#include <QNetworkReply>
40#include <QNetworkRequest>
48QgsSvgCacheEntry::QgsSvgCacheEntry(
const QString &path,
double size,
double strokeWidth,
double widthScaleFactor,
const QColor &fill,
const QColor &stroke,
double fixedAspectRatio,
const QMap<QString, QString> ¶meters )
51 , strokeWidth( strokeWidth )
52 , widthScaleFactor( widthScaleFactor )
53 , fixedAspectRatio( fixedAspectRatio )
56 , parameters( parameters )
62 const QgsSvgCacheEntry *otherSvg =
dynamic_cast< const QgsSvgCacheEntry *
>( other );
65 || !
qgsDoubleNear( otherSvg->fixedAspectRatio, fixedAspectRatio )
68 || !
qgsDoubleNear( otherSvg->widthScaleFactor, widthScaleFactor )
69 || otherSvg->fill != fill
70 || otherSvg->stroke != stroke
71 || otherSvg->path != path
72 || otherSvg->parameters != parameters )
78int QgsSvgCacheEntry::dataSize()
const
80 int size = svgContent.size();
83 size += picture->size();
87 size += ( image->width() * image->height() * 32 );
92void QgsSvgCacheEntry::dump()
const
94 QgsDebugMsgLevel( QStringLiteral(
"path: %1, size %2, width scale factor %3" ).arg( path ).arg( size ).arg( widthScaleFactor ), 4 );
106 mMissingSvg = QStringLiteral(
"<svg width='10' height='10'><text x='5' y='10' font-size='10' text-anchor='middle'>?</text></svg>" ).toLatin1();
109 if ( QFile::exists( downloadingSvgPath ) )
111 QFile file( downloadingSvgPath );
112 if ( file.open( QIODevice::ReadOnly ) )
114 mFetchingSvg = file.readAll();
118 if ( mFetchingSvg.isEmpty() )
120 mFetchingSvg = QStringLiteral(
"<svg width='10' height='10'><text x='5' y='10' font-size='10' text-anchor='middle'>?</text></svg>" ).toLatin1();
126QImage
QgsSvgCache::svgAsImage(
const QString &file,
double size,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
127 double widthScaleFactor,
bool &fitsInCache,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters )
129 const QMutexLocker locker( &
mMutex );
132 QgsSvgCacheEntry *currentEntry = cacheEntry( file, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking );
139 if ( !currentEntry->image )
141 const QSvgRenderer r( currentEntry->svgContent );
142 double hwRatio = 1.0;
143 if ( r.viewBoxF().width() > 0 )
145 if ( currentEntry->fixedAspectRatio > 0 )
147 hwRatio = currentEntry->fixedAspectRatio;
151 hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
154 long cachedDataSize = 0;
155 cachedDataSize += currentEntry->svgContent.size();
156 cachedDataSize +=
static_cast< int >( currentEntry->size * currentEntry->size * hwRatio * 32 );
160 currentEntry->image.reset();
163 if ( !currentEntry->picture )
165 cachePicture( currentEntry,
false );
169 result = imageFromCachedPicture( *currentEntry );
173 cacheImage( currentEntry );
174 result = *( currentEntry->image );
180 result = *( currentEntry->image );
187 double widthScaleFactor,
bool forceVectorOutput,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters )
189 const QMutexLocker locker( &
mMutex );
191 QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking );
195 if ( !currentEntry->picture )
197 cachePicture( currentEntry, forceVectorOutput );
206 p.setData( currentEntry->picture->data(), currentEntry->picture->size() );
210QByteArray
QgsSvgCache::svgContent(
const QString &path,
double size,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
211 double widthScaleFactor,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters,
bool *isMissingImage )
213 const QMutexLocker locker( &
mMutex );
215 QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking, isMissingImage );
217 return currentEntry->svgContent;
221 double widthScaleFactor,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters )
223 const QMutexLocker locker( &
mMutex );
225 QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking );
226 return currentEntry->viewboxSize;
229void QgsSvgCache::containsParams(
const QString &path,
bool &hasFillParam, QColor &defaultFillColor,
bool &hasStrokeParam, QColor &defaultStrokeColor,
230 bool &hasStrokeWidthParam,
double &defaultStrokeWidth,
bool blocking )
const
232 bool hasDefaultFillColor =
false;
233 bool hasFillOpacityParam =
false;
234 bool hasDefaultFillOpacity =
false;
235 double defaultFillOpacity = 1.0;
236 bool hasDefaultStrokeColor =
false;
237 bool hasDefaultStrokeWidth =
false;
238 bool hasStrokeOpacityParam =
false;
239 bool hasDefaultStrokeOpacity =
false;
240 double defaultStrokeOpacity = 1.0;
242 containsParams( path, hasFillParam, hasDefaultFillColor, defaultFillColor,
243 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
244 hasStrokeParam, hasDefaultStrokeColor, defaultStrokeColor,
245 hasStrokeWidthParam, hasDefaultStrokeWidth, defaultStrokeWidth,
246 hasStrokeOpacityParam, hasDefaultStrokeOpacity, defaultStrokeOpacity,
251 bool &hasFillParam,
bool &hasDefaultFillParam, QColor &defaultFillColor,
252 bool &hasFillOpacityParam,
bool &hasDefaultFillOpacity,
double &defaultFillOpacity,
253 bool &hasStrokeParam,
bool &hasDefaultStrokeColor, QColor &defaultStrokeColor,
254 bool &hasStrokeWidthParam,
bool &hasDefaultStrokeWidth,
double &defaultStrokeWidth,
255 bool &hasStrokeOpacityParam,
bool &hasDefaultStrokeOpacity,
double &defaultStrokeOpacity,
256 bool blocking )
const
258 hasFillParam =
false;
259 hasFillOpacityParam =
false;
260 hasStrokeParam =
false;
261 hasStrokeWidthParam =
false;
262 hasStrokeOpacityParam =
false;
263 defaultFillColor = QColor( Qt::white );
264 defaultFillOpacity = 1.0;
265 defaultStrokeColor = QColor( Qt::black );
266 defaultStrokeWidth = 0.2;
267 defaultStrokeOpacity = 1.0;
269 hasDefaultFillParam =
false;
270 hasDefaultFillOpacity =
false;
271 hasDefaultStrokeColor =
false;
272 hasDefaultStrokeWidth =
false;
273 hasDefaultStrokeOpacity =
false;
276 if ( !svgDoc.setContent(
getContent( path, mMissingSvg, mFetchingSvg, blocking ) ) )
281 const QDomElement docElem = svgDoc.documentElement();
282 containsElemParams( docElem, hasFillParam, hasDefaultFillParam, defaultFillColor,
283 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
284 hasStrokeParam, hasDefaultStrokeColor, defaultStrokeColor,
285 hasStrokeWidthParam, hasDefaultStrokeWidth, defaultStrokeWidth,
286 hasStrokeOpacityParam, hasDefaultStrokeOpacity, defaultStrokeOpacity );
289void QgsSvgCache::replaceParamsAndCacheSvg( QgsSvgCacheEntry *entry,
bool blocking )
296 const QByteArray content =
getContent( entry->path, mMissingSvg, mFetchingSvg, blocking ) ;
297 entry->isMissingImage = content == mMissingSvg;
299 if ( !svgDoc.setContent( content ) )
305 QDomElement docElem = svgDoc.documentElement();
308 const double sizeScaleFactor = calcSizeScaleFactor( entry, docElem, viewboxSize );
309 entry->viewboxSize = viewboxSize;
310 replaceElemParams( docElem, entry->fill, entry->stroke, entry->strokeWidth * sizeScaleFactor, entry->parameters );
312 entry->svgContent = svgDoc.toByteArray( 0 );
317 entry->svgContent.replace(
"\n<tspan",
"<tspan" );
318 entry->svgContent.replace(
"</tspan>\n",
"</tspan>" );
323double QgsSvgCache::calcSizeScaleFactor( QgsSvgCacheEntry *entry,
const QDomElement &docElem, QSizeF &viewboxSize )
const
333 if ( docElem.tagName() == QLatin1String(
"svg" ) && docElem.hasAttribute( QStringLiteral(
"viewBox" ) ) )
335 viewBox = docElem.attribute( QStringLiteral(
"viewBox" ), QString() );
337 else if ( docElem.tagName() == QLatin1String(
"svg" ) && docElem.hasAttribute( QStringLiteral(
"viewbox" ) ) )
339 viewBox = docElem.attribute( QStringLiteral(
"viewbox" ), QString() );
343 const QDomElement svgElem = docElem.firstChildElement( QStringLiteral(
"svg" ) );
344 if ( !svgElem.isNull() )
346 if ( svgElem.hasAttribute( QStringLiteral(
"viewBox" ) ) )
347 viewBox = svgElem.attribute( QStringLiteral(
"viewBox" ), QString() );
348 else if ( svgElem.hasAttribute( QStringLiteral(
"viewbox" ) ) )
349 viewBox = svgElem.attribute( QStringLiteral(
"viewbox" ), QString() );
354 if ( viewBox.isEmpty() )
357 if ( docElem.tagName() == QLatin1String(
"svg" ) && docElem.hasAttribute( QStringLiteral(
"width" ) ) )
359 const QString widthString = docElem.attribute( QStringLiteral(
"width" ) );
360 const thread_local QRegularExpression measureRegEx( QStringLiteral(
"([\\d\\.]+).*?$" ) );
361 const QRegularExpressionMatch widthMatch = measureRegEx.match( widthString );
362 if ( widthMatch.hasMatch() )
364 const double width = widthMatch.captured( 1 ).toDouble();
365 const QString heightString = docElem.attribute( QStringLiteral(
"height" ) );
367 const QRegularExpressionMatch heightMatch = measureRegEx.match( heightString );
368 if ( heightMatch.hasMatch() )
370 const double height = heightMatch.captured( 1 ).toDouble();
371 viewboxSize = QSizeF( width, height );
372 return width / entry->size;
382 const QStringList parts = viewBox.split(
' ' );
383 if ( parts.count() != 4 )
386 bool heightOk =
false;
387 const double height = parts.at( 3 ).toDouble( &heightOk );
389 bool widthOk =
false;
390 const double width = parts.at( 2 ).toDouble( &widthOk );
394 viewboxSize = QSizeF( width, height );
395 return width / entry->size;
404 return getContent( path, mMissingSvg, mFetchingSvg, blocking );
411 const QString contentType = reply->header( QNetworkRequest::ContentTypeHeader ).toString();
412 if ( !contentType.startsWith( QLatin1String(
"image/svg+xml" ), Qt::CaseInsensitive )
413 && !contentType.startsWith( QLatin1String(
"text/plain" ), Qt::CaseInsensitive ) )
421void QgsSvgCache::cacheImage( QgsSvgCacheEntry *entry )
428 entry->image.reset();
432 const QSize imageSize = sizeForImage( *entry, viewBoxSize, scaledSize );
435 std::unique_ptr< QImage > image = std::make_unique< QImage >( imageSize, QImage::Format_ARGB32_Premultiplied );
438 const bool isFixedAR = entry->fixedAspectRatio > 0;
440 QPainter p( image.get() );
441 QSvgRenderer r( entry->svgContent );
442 if (
qgsDoubleNear( viewBoxSize.width(), viewBoxSize.height() ) )
448 QSizeF s( viewBoxSize );
449 s.scale( scaledSize.width(), scaledSize.height(), isFixedAR ? Qt::IgnoreAspectRatio : Qt::KeepAspectRatio );
450 const QRectF rect( ( imageSize.width() - s.width() ) / 2, ( imageSize.height() - s.height() ) / 2, s.width(), s.height() );
451 r.render( &p, rect );
454 mTotalSize += ( image->width() * image->height() * 32 );
455 entry->image = std::move( image );
458void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry,
bool forceVectorOutput )
460 Q_UNUSED( forceVectorOutput )
466 entry->picture.reset();
468 const bool isFixedAR = entry->fixedAspectRatio > 0;
471 std::unique_ptr< QPicture > picture = std::make_unique< QPicture >();
473 QSvgRenderer r( entry->svgContent );
474 double hwRatio = 1.0;
475 if ( r.viewBoxF().width() > 0 )
479 hwRatio = entry->fixedAspectRatio;
483 hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
487 const double wSize = entry->size;
488 const double hSize = wSize * hwRatio;
490 QSizeF s( r.viewBoxF().size() );
491 s.scale( wSize, hSize, isFixedAR ? Qt::IgnoreAspectRatio : Qt::KeepAspectRatio );
492 rect = QRectF( -s.width() / 2.0, -s.height() / 2.0, s.width(), s.height() );
494 QPainter p( picture.get() );
495 r.render( &p, rect );
496 entry->picture = std::move( picture );
500QgsSvgCacheEntry *QgsSvgCache::cacheEntry(
const QString &path,
double size,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
501 double widthScaleFactor,
double fixedAspectRatio,
const QMap<QString, QString> ¶meters,
bool blocking,
bool *isMissingImage )
503 QgsSvgCacheEntry *currentEntry =
findExistingEntry(
new QgsSvgCacheEntry( path, size, strokeWidth, widthScaleFactor, fill, stroke, fixedAspectRatio, parameters ) );
505 if ( currentEntry->svgContent.isEmpty() )
507 replaceParamsAndCacheSvg( currentEntry, blocking );
510 if ( isMissingImage )
511 *isMissingImage = currentEntry->isMissingImage;
517void QgsSvgCache::replaceElemParams( QDomElement &elem,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
const QMap<QString, QString> ¶meters )
525 const QDomNamedNodeMap attributes = elem.attributes();
526 const int nAttributes = attributes.count();
527 for (
int i = 0; i < nAttributes; ++i )
529 const QDomAttr attribute = attributes.item( i ).toAttr();
531 if ( attribute.name().compare( QLatin1String(
"style" ), Qt::CaseInsensitive ) == 0 )
534 QString newAttributeString;
536 const QStringList entryList = attribute.value().split(
';' );
537 QStringList::const_iterator entryIt = entryList.constBegin();
538 for ( ; entryIt != entryList.constEnd(); ++entryIt )
540 const QStringList keyValueSplit = entryIt->split(
':' );
541 if ( keyValueSplit.size() < 2 )
545 const QString key = keyValueSplit.at( 0 );
546 QString value = keyValueSplit.at( 1 );
547 QString newValue = value;
548 value = value.trimmed().toLower();
550 if ( value.startsWith( QLatin1String(
"param(fill)" ) ) )
552 newValue = fill.name();
554 else if ( value.startsWith( QLatin1String(
"param(fill-opacity)" ) ) )
556 newValue = QString::number( fill.alphaF() );
558 else if ( value.startsWith( QLatin1String(
"param(outline)" ) ) )
560 newValue = stroke.name();
562 else if ( value.startsWith( QLatin1String(
"param(outline-opacity)" ) ) )
564 newValue = QString::number( stroke.alphaF() );
566 else if ( value.startsWith( QLatin1String(
"param(outline-width)" ) ) )
568 newValue = QString::number( strokeWidth );
571 if ( entryIt != entryList.constBegin() )
573 newAttributeString.append(
';' );
575 newAttributeString.append( key +
':' + newValue );
577 elem.setAttribute( attribute.name(), newAttributeString );
581 const QString value = attribute.value().trimmed().toLower();
582 if ( value.startsWith( QLatin1String(
"param(fill)" ) ) )
584 elem.setAttribute( attribute.name(), fill.name() );
586 else if ( value.startsWith( QLatin1String(
"param(fill-opacity)" ) ) )
588 elem.setAttribute( attribute.name(), fill.alphaF() );
590 else if ( value.startsWith( QLatin1String(
"param(outline)" ) ) )
592 elem.setAttribute( attribute.name(), stroke.name() );
594 else if ( value.startsWith( QLatin1String(
"param(outline-opacity)" ) ) )
596 elem.setAttribute( attribute.name(), stroke.alphaF() );
598 else if ( value.startsWith( QLatin1String(
"param(outline-width)" ) ) )
600 elem.setAttribute( attribute.name(), QString::number( strokeWidth ) );
604 QMap<QString, QString>::const_iterator paramIt = parameters.constBegin();
605 for ( ; paramIt != parameters.constEnd(); ++paramIt )
607 if ( value.startsWith( QString( QLatin1String(
"param(%1)" ) ).arg( paramIt.key() ) ) )
609 elem.setAttribute( attribute.name(), paramIt.value() );
617 QDomNode child = elem.firstChild();
618 if ( child.isText() && child.nodeValue().startsWith(
"param(" ) )
620 QMap<QString, QString>::const_iterator paramIt = parameters.constBegin();
621 for ( ; paramIt != parameters.constEnd(); ++paramIt )
623 if ( child.toText().data().startsWith( QString( QLatin1String(
"param(%1)" ) ).arg( paramIt.key() ) ) )
625 child.setNodeValue( paramIt.value() );
631 const QDomNodeList childList = elem.childNodes();
632 const int nChildren = childList.count();
633 for (
int i = 0; i < nChildren; ++i )
635 QDomElement childElem = childList.at( i ).toElement();
636 replaceElemParams( childElem, fill, stroke, strokeWidth, parameters );
640void QgsSvgCache::containsElemParams(
const QDomElement &elem,
bool &hasFillParam,
bool &hasDefaultFill, QColor &defaultFill,
641 bool &hasFillOpacityParam,
bool &hasDefaultFillOpacity,
double &defaultFillOpacity,
642 bool &hasStrokeParam,
bool &hasDefaultStroke, QColor &defaultStroke,
643 bool &hasStrokeWidthParam,
bool &hasDefaultStrokeWidth,
double &defaultStrokeWidth,
644 bool &hasStrokeOpacityParam,
bool &hasDefaultStrokeOpacity,
double &defaultStrokeOpacity )
const
652 if ( hasFillParam && hasStrokeParam && hasStrokeWidthParam && hasFillOpacityParam && hasStrokeOpacityParam )
658 const QDomNamedNodeMap attributes = elem.attributes();
659 const int nAttributes = attributes.count();
661 QStringList valueSplit;
662 for (
int i = 0; i < nAttributes; ++i )
664 const QDomAttr attribute = attributes.item( i ).toAttr();
665 if ( attribute.name().compare( QLatin1String(
"style" ), Qt::CaseInsensitive ) == 0 )
668 const QStringList entryList = attribute.value().split(
';' );
669 QStringList::const_iterator entryIt = entryList.constBegin();
670 for ( ; entryIt != entryList.constEnd(); ++entryIt )
672 const QStringList keyValueSplit = entryIt->split(
':' );
673 if ( keyValueSplit.size() < 2 )
677 const QString value = keyValueSplit.at( 1 );
678 valueSplit = value.split(
' ' );
679 if ( !hasFillParam && value.startsWith( QLatin1String(
"param(fill)" ) ) )
682 if ( valueSplit.size() > 1 )
684 defaultFill = QColor( valueSplit.at( 1 ) );
685 hasDefaultFill =
true;
688 else if ( !hasFillOpacityParam && value.startsWith( QLatin1String(
"param(fill-opacity)" ) ) )
690 hasFillOpacityParam =
true;
691 if ( valueSplit.size() > 1 )
694 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
697 defaultFillOpacity = opacity;
698 hasDefaultFillOpacity =
true;
702 else if ( !hasStrokeParam && value.startsWith( QLatin1String(
"param(outline)" ) ) )
704 hasStrokeParam =
true;
705 if ( valueSplit.size() > 1 )
707 defaultStroke = QColor( valueSplit.at( 1 ) );
708 hasDefaultStroke =
true;
711 else if ( !hasStrokeWidthParam && value.startsWith( QLatin1String(
"param(outline-width)" ) ) )
713 hasStrokeWidthParam =
true;
714 if ( valueSplit.size() > 1 )
716 defaultStrokeWidth = valueSplit.at( 1 ).toDouble();
717 hasDefaultStrokeWidth =
true;
720 else if ( !hasStrokeOpacityParam && value.startsWith( QLatin1String(
"param(outline-opacity)" ) ) )
722 hasStrokeOpacityParam =
true;
723 if ( valueSplit.size() > 1 )
726 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
729 defaultStrokeOpacity = opacity;
730 hasDefaultStrokeOpacity =
true;
738 const QString value = attribute.value();
739 valueSplit = value.split(
' ' );
740 if ( !hasFillParam && value.startsWith( QLatin1String(
"param(fill)" ) ) )
743 if ( valueSplit.size() > 1 )
745 defaultFill = QColor( valueSplit.at( 1 ) );
746 hasDefaultFill =
true;
749 else if ( !hasFillOpacityParam && value.startsWith( QLatin1String(
"param(fill-opacity)" ) ) )
751 hasFillOpacityParam =
true;
752 if ( valueSplit.size() > 1 )
755 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
758 defaultFillOpacity = opacity;
759 hasDefaultFillOpacity =
true;
763 else if ( !hasStrokeParam && value.startsWith( QLatin1String(
"param(outline)" ) ) )
765 hasStrokeParam =
true;
766 if ( valueSplit.size() > 1 )
768 defaultStroke = QColor( valueSplit.at( 1 ) );
769 hasDefaultStroke =
true;
772 else if ( !hasStrokeWidthParam && value.startsWith( QLatin1String(
"param(outline-width)" ) ) )
774 hasStrokeWidthParam =
true;
775 if ( valueSplit.size() > 1 )
777 defaultStrokeWidth = valueSplit.at( 1 ).toDouble();
778 hasDefaultStrokeWidth =
true;
781 else if ( !hasStrokeOpacityParam && value.startsWith( QLatin1String(
"param(outline-opacity)" ) ) )
783 hasStrokeOpacityParam =
true;
784 if ( valueSplit.size() > 1 )
787 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
790 defaultStrokeOpacity = opacity;
791 hasDefaultStrokeOpacity =
true;
799 const QDomNodeList childList = elem.childNodes();
800 const int nChildren = childList.count();
801 for (
int i = 0; i < nChildren; ++i )
803 const QDomElement childElem = childList.at( i ).toElement();
804 containsElemParams( childElem, hasFillParam, hasDefaultFill, defaultFill,
805 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
806 hasStrokeParam, hasDefaultStroke, defaultStroke,
807 hasStrokeWidthParam, hasDefaultStrokeWidth, defaultStrokeWidth,
808 hasStrokeOpacityParam, hasDefaultStrokeOpacity, defaultStrokeOpacity );
812QSize QgsSvgCache::sizeForImage(
const QgsSvgCacheEntry &entry, QSizeF &viewBoxSize, QSizeF &scaledSize )
const
814 const bool isFixedAR = entry.fixedAspectRatio > 0;
816 const QSvgRenderer r( entry.svgContent );
817 double hwRatio = 1.0;
818 viewBoxSize = r.viewBoxF().size();
819 if ( viewBoxSize.width() > 0 )
823 hwRatio = entry.fixedAspectRatio;
827 hwRatio = viewBoxSize.height() / viewBoxSize.width();
832 scaledSize.setWidth( entry.size );
833 int wImgSize =
static_cast< int >( scaledSize.width() );
838 scaledSize.setHeight( scaledSize.width() * hwRatio );
839 int hImgSize =
static_cast< int >( scaledSize.height() );
844 return QSize( wImgSize, hImgSize );
847QImage QgsSvgCache::imageFromCachedPicture(
const QgsSvgCacheEntry &entry )
const
851 QImage image( sizeForImage( entry, viewBoxSize, scaledSize ), QImage::Format_ARGB32_Premultiplied );
854 QPainter p( &image );
855 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.
long mMaxCacheSize
Maximum cache size.
QByteArray getContent(const QString &path, const QByteArray &missingContent, const QByteArray &fetchingContent, bool blocking=false) const
Gets the file content corresponding to the given path.
QgsSvgCacheEntry * findExistingEntry(QgsSvgCacheEntry *entryTemplate)
Returns the existing entry from the cache which matches entryTemplate (deleting entryTemplate when do...
long mTotalSize
Estimated total size of all cached content.
void trimToMaximumSize()
Removes the least used cache entries until the maximum cache size is under the predefined size limit.
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)
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)