19#include "moc_qgssvgcache.cpp"
28#include <QApplication>
29#include <QCoreApplication>
31#include <QDomDocument>
37#include <QRegularExpression>
38#include <QSvgRenderer>
40#include <QNetworkReply>
41#include <QNetworkRequest>
49QgsSvgCacheEntry::QgsSvgCacheEntry(
const QString &path,
double size,
double strokeWidth,
double widthScaleFactor,
const QColor &fill,
const QColor &stroke,
double fixedAspectRatio,
const QMap<QString, QString> ¶meters )
52 , strokeWidth( strokeWidth )
53 , widthScaleFactor( widthScaleFactor )
54 , fixedAspectRatio( fixedAspectRatio )
57 , parameters( parameters )
63 const QgsSvgCacheEntry *otherSvg =
dynamic_cast< const QgsSvgCacheEntry *
>( other );
66 || !
qgsDoubleNear( otherSvg->fixedAspectRatio, fixedAspectRatio )
69 || !
qgsDoubleNear( otherSvg->widthScaleFactor, widthScaleFactor )
70 || otherSvg->fill != fill
71 || otherSvg->stroke != stroke
72 || otherSvg->path != path
73 || otherSvg->parameters != parameters )
79int QgsSvgCacheEntry::dataSize()
const
81 int size = svgContent.size();
84 size += picture->size();
88 size += ( image->width() * image->height() * 32 );
93void QgsSvgCacheEntry::dump()
const
95 QgsDebugMsgLevel( QStringLiteral(
"path: %1, size %2, width scale factor %3" ).arg( path ).arg( size ).arg( widthScaleFactor ), 4 );
107 mMissingSvg = QStringLiteral(
"<svg width='10' height='10'><text x='5' y='10' font-size='10' text-anchor='middle'>?</text></svg>" ).toLatin1();
110 if ( QFile::exists( downloadingSvgPath ) )
112 QFile file( downloadingSvgPath );
113 if ( file.open( QIODevice::ReadOnly ) )
115 mFetchingSvg = file.readAll();
119 if ( mFetchingSvg.isEmpty() )
121 mFetchingSvg = QStringLiteral(
"<svg width='10' height='10'><text x='5' y='10' font-size='10' text-anchor='middle'>?</text></svg>" ).toLatin1();
127QImage
QgsSvgCache::svgAsImage(
const QString &file,
double size,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
128 double widthScaleFactor,
bool &fitsInCache,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters )
130 const QMutexLocker locker( &
mMutex );
133 QgsSvgCacheEntry *currentEntry = cacheEntry( file, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking );
140 if ( !currentEntry->image )
142 const QSvgRenderer r( currentEntry->svgContent );
143 double hwRatio = 1.0;
144 if ( r.viewBoxF().width() > 0 )
146 if ( currentEntry->fixedAspectRatio > 0 )
148 hwRatio = currentEntry->fixedAspectRatio;
152 hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
155 long cachedDataSize = 0;
156 cachedDataSize += currentEntry->svgContent.size();
157 cachedDataSize +=
static_cast< int >( currentEntry->size * currentEntry->size * hwRatio * 32 );
161 currentEntry->image.reset();
164 if ( !currentEntry->picture )
166 cachePicture( currentEntry,
false );
170 result = imageFromCachedPicture( *currentEntry );
174 cacheImage( currentEntry );
175 result = *( currentEntry->image );
181 result = *( currentEntry->image );
188 double widthScaleFactor,
bool forceVectorOutput,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters )
190 const QMutexLocker locker( &
mMutex );
192 QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking );
196 if ( !currentEntry->picture )
198 cachePicture( currentEntry, forceVectorOutput );
207 p.setData( currentEntry->picture->data(), currentEntry->picture->size() );
211QByteArray
QgsSvgCache::svgContent(
const QString &path,
double size,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
212 double widthScaleFactor,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters,
bool *isMissingImage )
214 const QMutexLocker locker( &
mMutex );
216 QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking, isMissingImage );
218 return currentEntry->svgContent;
222 double widthScaleFactor,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters )
224 const QMutexLocker locker( &
mMutex );
226 QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking );
227 return currentEntry->viewboxSize;
230void QgsSvgCache::containsParams(
const QString &path,
bool &hasFillParam, QColor &defaultFillColor,
bool &hasStrokeParam, QColor &defaultStrokeColor,
231 bool &hasStrokeWidthParam,
double &defaultStrokeWidth,
bool blocking )
const
233 bool hasDefaultFillColor =
false;
234 bool hasFillOpacityParam =
false;
235 bool hasDefaultFillOpacity =
false;
236 double defaultFillOpacity = 1.0;
237 bool hasDefaultStrokeColor =
false;
238 bool hasDefaultStrokeWidth =
false;
239 bool hasStrokeOpacityParam =
false;
240 bool hasDefaultStrokeOpacity =
false;
241 double defaultStrokeOpacity = 1.0;
243 containsParams( path, hasFillParam, hasDefaultFillColor, defaultFillColor,
244 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
245 hasStrokeParam, hasDefaultStrokeColor, defaultStrokeColor,
246 hasStrokeWidthParam, hasDefaultStrokeWidth, defaultStrokeWidth,
247 hasStrokeOpacityParam, hasDefaultStrokeOpacity, defaultStrokeOpacity,
252 bool &hasFillParam,
bool &hasDefaultFillParam, QColor &defaultFillColor,
253 bool &hasFillOpacityParam,
bool &hasDefaultFillOpacity,
double &defaultFillOpacity,
254 bool &hasStrokeParam,
bool &hasDefaultStrokeColor, QColor &defaultStrokeColor,
255 bool &hasStrokeWidthParam,
bool &hasDefaultStrokeWidth,
double &defaultStrokeWidth,
256 bool &hasStrokeOpacityParam,
bool &hasDefaultStrokeOpacity,
double &defaultStrokeOpacity,
257 bool blocking )
const
259 hasFillParam =
false;
260 hasFillOpacityParam =
false;
261 hasStrokeParam =
false;
262 hasStrokeWidthParam =
false;
263 hasStrokeOpacityParam =
false;
264 defaultFillColor = QColor( Qt::white );
265 defaultFillOpacity = 1.0;
266 defaultStrokeColor = QColor( Qt::black );
267 defaultStrokeWidth = 0.2;
268 defaultStrokeOpacity = 1.0;
270 hasDefaultFillParam =
false;
271 hasDefaultFillOpacity =
false;
272 hasDefaultStrokeColor =
false;
273 hasDefaultStrokeWidth =
false;
274 hasDefaultStrokeOpacity =
false;
277 if ( !svgDoc.setContent(
getContent( path, mMissingSvg, mFetchingSvg, blocking ) ) )
282 const QDomElement docElem = svgDoc.documentElement();
283 containsElemParams( docElem, hasFillParam, hasDefaultFillParam, defaultFillColor,
284 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
285 hasStrokeParam, hasDefaultStrokeColor, defaultStrokeColor,
286 hasStrokeWidthParam, hasDefaultStrokeWidth, defaultStrokeWidth,
287 hasStrokeOpacityParam, hasDefaultStrokeOpacity, defaultStrokeOpacity );
290void QgsSvgCache::replaceParamsAndCacheSvg( QgsSvgCacheEntry *entry,
bool blocking )
297 const QByteArray content =
getContent( entry->path, mMissingSvg, mFetchingSvg, blocking ) ;
298 entry->isMissingImage = content == mMissingSvg;
300 if ( !svgDoc.setContent( content ) )
306 QDomElement docElem = svgDoc.documentElement();
309 const double sizeScaleFactor = calcSizeScaleFactor( entry, docElem, viewboxSize );
310 entry->viewboxSize = viewboxSize;
311 replaceElemParams( docElem, entry->fill, entry->stroke, entry->strokeWidth * sizeScaleFactor, entry->parameters );
313 entry->svgContent = svgDoc.toByteArray( 0 );
318 entry->svgContent.replace(
"\n<tspan",
"<tspan" );
319 entry->svgContent.replace(
"</tspan>\n",
"</tspan>" );
324double QgsSvgCache::calcSizeScaleFactor( QgsSvgCacheEntry *entry,
const QDomElement &docElem, QSizeF &viewboxSize )
const
334 if ( docElem.tagName() == QLatin1String(
"svg" ) && docElem.hasAttribute( QStringLiteral(
"viewBox" ) ) )
336 viewBox = docElem.attribute( QStringLiteral(
"viewBox" ), QString() );
338 else if ( docElem.tagName() == QLatin1String(
"svg" ) && docElem.hasAttribute( QStringLiteral(
"viewbox" ) ) )
340 viewBox = docElem.attribute( QStringLiteral(
"viewbox" ), QString() );
344 const QDomElement svgElem = docElem.firstChildElement( QStringLiteral(
"svg" ) );
345 if ( !svgElem.isNull() )
347 if ( svgElem.hasAttribute( QStringLiteral(
"viewBox" ) ) )
348 viewBox = svgElem.attribute( QStringLiteral(
"viewBox" ), QString() );
349 else if ( svgElem.hasAttribute( QStringLiteral(
"viewbox" ) ) )
350 viewBox = svgElem.attribute( QStringLiteral(
"viewbox" ), QString() );
355 if ( viewBox.isEmpty() )
358 if ( docElem.tagName() == QLatin1String(
"svg" ) && docElem.hasAttribute( QStringLiteral(
"width" ) ) )
360 const QString widthString = docElem.attribute( QStringLiteral(
"width" ) );
361 const thread_local QRegularExpression measureRegEx( QStringLiteral(
"([\\d\\.]+).*?$" ) );
362 const QRegularExpressionMatch widthMatch = measureRegEx.match( widthString );
363 if ( widthMatch.hasMatch() )
365 const double width = widthMatch.captured( 1 ).toDouble();
366 const QString heightString = docElem.attribute( QStringLiteral(
"height" ) );
368 const QRegularExpressionMatch heightMatch = measureRegEx.match( heightString );
369 if ( heightMatch.hasMatch() )
371 const double height = heightMatch.captured( 1 ).toDouble();
372 viewboxSize = QSizeF( width, height );
373 return width / entry->size;
383 const QStringList parts = viewBox.split(
' ' );
384 if ( parts.count() != 4 )
387 bool heightOk =
false;
388 const double height = parts.at( 3 ).toDouble( &heightOk );
390 bool widthOk =
false;
391 const double width = parts.at( 2 ).toDouble( &widthOk );
395 viewboxSize = QSizeF( width, height );
396 return width / entry->size;
405 return getContent( path, mMissingSvg, mFetchingSvg, blocking );
412 const QString contentType = reply->header( QNetworkRequest::ContentTypeHeader ).toString();
413 if ( !contentType.startsWith( QLatin1String(
"image/svg+xml" ), Qt::CaseInsensitive )
414 && !contentType.startsWith( QLatin1String(
"text/plain" ), Qt::CaseInsensitive ) )
422void QgsSvgCache::cacheImage( QgsSvgCacheEntry *entry )
429 entry->image.reset();
433 const QSize imageSize = sizeForImage( *entry, viewBoxSize, scaledSize );
436 std::unique_ptr< QImage > image = std::make_unique< QImage >( imageSize, QImage::Format_ARGB32_Premultiplied );
439 const bool isFixedAR = entry->fixedAspectRatio > 0;
441 QPainter p( image.get() );
442 QSvgRenderer r( entry->svgContent );
443 if (
qgsDoubleNear( viewBoxSize.width(), viewBoxSize.height() ) )
449 QSizeF s( viewBoxSize );
450 s.scale( scaledSize.width(), scaledSize.height(), isFixedAR ? Qt::IgnoreAspectRatio : Qt::KeepAspectRatio );
451 const QRectF rect( ( imageSize.width() - s.width() ) / 2, ( imageSize.height() - s.height() ) / 2, s.width(), s.height() );
452 r.render( &p, rect );
455 mTotalSize += ( image->width() * image->height() * 32 );
456 entry->image = std::move( image );
459void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry,
bool forceVectorOutput )
461 Q_UNUSED( forceVectorOutput )
467 entry->picture.reset();
469 const bool isFixedAR = entry->fixedAspectRatio > 0;
472 std::unique_ptr< QPicture > picture = std::make_unique< QPicture >();
474 QSvgRenderer r( entry->svgContent );
475 double hwRatio = 1.0;
476 if ( r.viewBoxF().width() > 0 )
480 hwRatio = entry->fixedAspectRatio;
484 hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
488 const double wSize = entry->size;
489 const double hSize = wSize * hwRatio;
491 QSizeF s( r.viewBoxF().size() );
492 s.scale( wSize, hSize, isFixedAR ? Qt::IgnoreAspectRatio : Qt::KeepAspectRatio );
493 rect = QRectF( -s.width() / 2.0, -s.height() / 2.0, s.width(), s.height() );
495 QPainter p( picture.get() );
496 r.render( &p, rect );
497 entry->picture = std::move( picture );
501QgsSvgCacheEntry *QgsSvgCache::cacheEntry(
const QString &path,
double size,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
502 double widthScaleFactor,
double fixedAspectRatio,
const QMap<QString, QString> ¶meters,
bool blocking,
bool *isMissingImage )
504 QgsSvgCacheEntry *currentEntry =
findExistingEntry(
new QgsSvgCacheEntry( path, size, strokeWidth, widthScaleFactor, fill, stroke, fixedAspectRatio, parameters ) );
506 if ( currentEntry->svgContent.isEmpty() )
508 replaceParamsAndCacheSvg( currentEntry, blocking );
511 if ( isMissingImage )
512 *isMissingImage = currentEntry->isMissingImage;
518void QgsSvgCache::replaceElemParams( QDomElement &elem,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
const QMap<QString, QString> ¶meters )
526 const QDomNamedNodeMap attributes = elem.attributes();
527 const int nAttributes = attributes.count();
528 for (
int i = 0; i < nAttributes; ++i )
530 const QDomAttr attribute = attributes.item( i ).toAttr();
532 if ( attribute.name().compare( QLatin1String(
"style" ), Qt::CaseInsensitive ) == 0 )
535 QString newAttributeString;
537 const QStringList entryList = attribute.value().split(
';' );
538 QStringList::const_iterator entryIt = entryList.constBegin();
539 for ( ; entryIt != entryList.constEnd(); ++entryIt )
541 const QStringList keyValueSplit = entryIt->split(
':' );
542 if ( keyValueSplit.size() < 2 )
546 const QString key = keyValueSplit.at( 0 );
547 QString value = keyValueSplit.at( 1 );
548 QString newValue = value;
549 value = value.trimmed().toLower();
551 if ( value.startsWith( QLatin1String(
"param(fill)" ) ) )
553 newValue = fill.name();
555 else if ( value.startsWith( QLatin1String(
"param(fill-opacity)" ) ) )
557 newValue = QString::number( fill.alphaF() );
559 else if ( value.startsWith( QLatin1String(
"param(outline)" ) ) )
561 newValue = stroke.name();
563 else if ( value.startsWith( QLatin1String(
"param(outline-opacity)" ) ) )
565 newValue = QString::number( stroke.alphaF() );
567 else if ( value.startsWith( QLatin1String(
"param(outline-width)" ) ) )
569 newValue = QString::number( strokeWidth );
572 if ( entryIt != entryList.constBegin() )
574 newAttributeString.append(
';' );
576 newAttributeString.append( key +
':' + newValue );
578 elem.setAttribute( attribute.name(), newAttributeString );
582 const QString value = attribute.value().trimmed().toLower();
583 if ( value.startsWith( QLatin1String(
"param(fill)" ) ) )
585 elem.setAttribute( attribute.name(), fill.name() );
587 else if ( value.startsWith( QLatin1String(
"param(fill-opacity)" ) ) )
589 elem.setAttribute( attribute.name(), fill.alphaF() );
591 else if ( value.startsWith( QLatin1String(
"param(outline)" ) ) )
593 elem.setAttribute( attribute.name(), stroke.name() );
595 else if ( value.startsWith( QLatin1String(
"param(outline-opacity)" ) ) )
597 elem.setAttribute( attribute.name(), stroke.alphaF() );
599 else if ( value.startsWith( QLatin1String(
"param(outline-width)" ) ) )
601 elem.setAttribute( attribute.name(), QString::number( strokeWidth ) );
605 QMap<QString, QString>::const_iterator paramIt = parameters.constBegin();
606 for ( ; paramIt != parameters.constEnd(); ++paramIt )
608 if ( value.startsWith( QString( QLatin1String(
"param(%1)" ) ).arg( paramIt.key() ) ) )
610 elem.setAttribute( attribute.name(), paramIt.value() );
618 QDomNode child = elem.firstChild();
619 if ( child.isText() && child.nodeValue().startsWith(
"param(" ) )
621 QMap<QString, QString>::const_iterator paramIt = parameters.constBegin();
622 for ( ; paramIt != parameters.constEnd(); ++paramIt )
624 if ( child.toText().data().startsWith( QString( QLatin1String(
"param(%1)" ) ).arg( paramIt.key() ) ) )
626 child.setNodeValue( paramIt.value() );
632 const QDomNodeList childList = elem.childNodes();
633 const int nChildren = childList.count();
634 for (
int i = 0; i < nChildren; ++i )
636 QDomElement childElem = childList.at( i ).toElement();
637 replaceElemParams( childElem, fill, stroke, strokeWidth, parameters );
641void QgsSvgCache::containsElemParams(
const QDomElement &elem,
bool &hasFillParam,
bool &hasDefaultFill, QColor &defaultFill,
642 bool &hasFillOpacityParam,
bool &hasDefaultFillOpacity,
double &defaultFillOpacity,
643 bool &hasStrokeParam,
bool &hasDefaultStroke, QColor &defaultStroke,
644 bool &hasStrokeWidthParam,
bool &hasDefaultStrokeWidth,
double &defaultStrokeWidth,
645 bool &hasStrokeOpacityParam,
bool &hasDefaultStrokeOpacity,
double &defaultStrokeOpacity )
const
653 if ( hasFillParam && hasStrokeParam && hasStrokeWidthParam && hasFillOpacityParam && hasStrokeOpacityParam )
659 const QDomNamedNodeMap attributes = elem.attributes();
660 const int nAttributes = attributes.count();
662 QStringList valueSplit;
663 for (
int i = 0; i < nAttributes; ++i )
665 const QDomAttr attribute = attributes.item( i ).toAttr();
666 if ( attribute.name().compare( QLatin1String(
"style" ), Qt::CaseInsensitive ) == 0 )
669 const QStringList entryList = attribute.value().split(
';' );
670 QStringList::const_iterator entryIt = entryList.constBegin();
671 for ( ; entryIt != entryList.constEnd(); ++entryIt )
673 const QStringList keyValueSplit = entryIt->split(
':' );
674 if ( keyValueSplit.size() < 2 )
678 const QString value = keyValueSplit.at( 1 );
679 valueSplit = value.split(
' ' );
680 if ( !hasFillParam && value.startsWith( QLatin1String(
"param(fill)" ) ) )
683 if ( valueSplit.size() > 1 )
685 defaultFill = QColor( valueSplit.at( 1 ) );
686 hasDefaultFill =
true;
689 else if ( !hasFillOpacityParam && value.startsWith( QLatin1String(
"param(fill-opacity)" ) ) )
691 hasFillOpacityParam =
true;
692 if ( valueSplit.size() > 1 )
695 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
698 defaultFillOpacity = opacity;
699 hasDefaultFillOpacity =
true;
703 else if ( !hasStrokeParam && value.startsWith( QLatin1String(
"param(outline)" ) ) )
705 hasStrokeParam =
true;
706 if ( valueSplit.size() > 1 )
708 defaultStroke = QColor( valueSplit.at( 1 ) );
709 hasDefaultStroke =
true;
712 else if ( !hasStrokeWidthParam && value.startsWith( QLatin1String(
"param(outline-width)" ) ) )
714 hasStrokeWidthParam =
true;
715 if ( valueSplit.size() > 1 )
717 defaultStrokeWidth = valueSplit.at( 1 ).toDouble();
718 hasDefaultStrokeWidth =
true;
721 else if ( !hasStrokeOpacityParam && value.startsWith( QLatin1String(
"param(outline-opacity)" ) ) )
723 hasStrokeOpacityParam =
true;
724 if ( valueSplit.size() > 1 )
727 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
730 defaultStrokeOpacity = opacity;
731 hasDefaultStrokeOpacity =
true;
739 const QString value = attribute.value();
740 valueSplit = value.split(
' ' );
741 if ( !hasFillParam && value.startsWith( QLatin1String(
"param(fill)" ) ) )
744 if ( valueSplit.size() > 1 )
746 defaultFill = QColor( valueSplit.at( 1 ) );
747 hasDefaultFill =
true;
750 else if ( !hasFillOpacityParam && value.startsWith( QLatin1String(
"param(fill-opacity)" ) ) )
752 hasFillOpacityParam =
true;
753 if ( valueSplit.size() > 1 )
756 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
759 defaultFillOpacity = opacity;
760 hasDefaultFillOpacity =
true;
764 else if ( !hasStrokeParam && value.startsWith( QLatin1String(
"param(outline)" ) ) )
766 hasStrokeParam =
true;
767 if ( valueSplit.size() > 1 )
769 defaultStroke = QColor( valueSplit.at( 1 ) );
770 hasDefaultStroke =
true;
773 else if ( !hasStrokeWidthParam && value.startsWith( QLatin1String(
"param(outline-width)" ) ) )
775 hasStrokeWidthParam =
true;
776 if ( valueSplit.size() > 1 )
778 defaultStrokeWidth = valueSplit.at( 1 ).toDouble();
779 hasDefaultStrokeWidth =
true;
782 else if ( !hasStrokeOpacityParam && value.startsWith( QLatin1String(
"param(outline-opacity)" ) ) )
784 hasStrokeOpacityParam =
true;
785 if ( valueSplit.size() > 1 )
788 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
791 defaultStrokeOpacity = opacity;
792 hasDefaultStrokeOpacity =
true;
800 const QDomNodeList childList = elem.childNodes();
801 const int nChildren = childList.count();
802 for (
int i = 0; i < nChildren; ++i )
804 const QDomElement childElem = childList.at( i ).toElement();
805 containsElemParams( childElem, hasFillParam, hasDefaultFill, defaultFill,
806 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
807 hasStrokeParam, hasDefaultStroke, defaultStroke,
808 hasStrokeWidthParam, hasDefaultStrokeWidth, defaultStrokeWidth,
809 hasStrokeOpacityParam, hasDefaultStrokeOpacity, defaultStrokeOpacity );
813QSize QgsSvgCache::sizeForImage(
const QgsSvgCacheEntry &entry, QSizeF &viewBoxSize, QSizeF &scaledSize )
const
815 const bool isFixedAR = entry.fixedAspectRatio > 0;
817 const QSvgRenderer r( entry.svgContent );
818 double hwRatio = 1.0;
819 viewBoxSize = r.viewBoxF().size();
820 if ( viewBoxSize.width() > 0 )
824 hwRatio = entry.fixedAspectRatio;
828 hwRatio = viewBoxSize.height() / viewBoxSize.width();
833 scaledSize.setWidth( entry.size );
834 int wImgSize =
static_cast< int >( scaledSize.width() );
839 scaledSize.setHeight( scaledSize.width() * hwRatio );
840 int hImgSize =
static_cast< int >( scaledSize.height() );
845 return QSize( wImgSize, hImgSize );
848QImage QgsSvgCache::imageFromCachedPicture(
const QgsSvgCacheEntry &entry )
const
852 QImage image( sizeForImage( entry, viewBoxSize, scaledSize ), QImage::Format_ARGB32_Premultiplied );
855 QPainter p( &image );
856 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)