26#include <QApplication>
27#include <QCoreApplication>
29#include <QDomDocument>
35#include <QRegularExpression>
36#include <QSvgRenderer>
38#include <QNetworkReply>
39#include <QNetworkRequest>
47QgsSvgCacheEntry::QgsSvgCacheEntry(
const QString &path,
double size,
double strokeWidth,
double widthScaleFactor,
const QColor &fill,
const QColor &stroke,
double fixedAspectRatio,
const QMap<QString, QString> ¶meters )
50 , strokeWidth( strokeWidth )
51 , widthScaleFactor( widthScaleFactor )
52 , fixedAspectRatio( fixedAspectRatio )
55 , parameters( parameters )
61 const QgsSvgCacheEntry *otherSvg =
dynamic_cast< const QgsSvgCacheEntry *
>( other );
64 || !
qgsDoubleNear( otherSvg->fixedAspectRatio, fixedAspectRatio )
67 || !
qgsDoubleNear( otherSvg->widthScaleFactor, widthScaleFactor )
68 || otherSvg->fill != fill
69 || otherSvg->stroke != stroke
70 || otherSvg->path != path
71 || otherSvg->parameters != parameters )
77int QgsSvgCacheEntry::dataSize()
const
79 int size = svgContent.size();
82 size += picture->size();
86 size += ( image->width() * image->height() * 32 );
91void QgsSvgCacheEntry::dump()
const
93 QgsDebugMsgLevel( QStringLiteral(
"path: %1, size %2, width scale factor %3" ).arg( path ).arg( size ).arg( widthScaleFactor ), 4 );
105 mMissingSvg = QStringLiteral(
"<svg width='10' height='10'><text x='5' y='10' font-size='10' text-anchor='middle'>?</text></svg>" ).toLatin1();
108 if ( QFile::exists( downloadingSvgPath ) )
110 QFile file( downloadingSvgPath );
111 if ( file.open( QIODevice::ReadOnly ) )
113 mFetchingSvg = file.readAll();
117 if ( mFetchingSvg.isEmpty() )
119 mFetchingSvg = QStringLiteral(
"<svg width='10' height='10'><text x='5' y='10' font-size='10' text-anchor='middle'>?</text></svg>" ).toLatin1();
125QImage
QgsSvgCache::svgAsImage(
const QString &file,
double size,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
126 double widthScaleFactor,
bool &fitsInCache,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters )
128 const QMutexLocker locker( &
mMutex );
131 QgsSvgCacheEntry *currentEntry = cacheEntry( file, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking );
138 if ( !currentEntry->image )
140 const QSvgRenderer r( currentEntry->svgContent );
141 double hwRatio = 1.0;
142 if ( r.viewBoxF().width() > 0 )
144 if ( currentEntry->fixedAspectRatio > 0 )
146 hwRatio = currentEntry->fixedAspectRatio;
150 hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
153 long cachedDataSize = 0;
154 cachedDataSize += currentEntry->svgContent.size();
155 cachedDataSize +=
static_cast< int >( currentEntry->size * currentEntry->size * hwRatio * 32 );
159 currentEntry->image.reset();
162 if ( !currentEntry->picture )
164 cachePicture( currentEntry,
false );
168 result = imageFromCachedPicture( *currentEntry );
172 cacheImage( currentEntry );
173 result = *( currentEntry->image );
179 result = *( currentEntry->image );
186 double widthScaleFactor,
bool forceVectorOutput,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters )
188 const QMutexLocker locker( &
mMutex );
190 QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking );
194 if ( !currentEntry->picture )
196 cachePicture( currentEntry, forceVectorOutput );
205 p.setData( currentEntry->picture->data(), currentEntry->picture->size() );
209QByteArray
QgsSvgCache::svgContent(
const QString &path,
double size,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
210 double widthScaleFactor,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters,
bool *isMissingImage )
212 const QMutexLocker locker( &
mMutex );
214 QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking, isMissingImage );
216 return currentEntry->svgContent;
220 double widthScaleFactor,
double fixedAspectRatio,
bool blocking,
const QMap<QString, QString> ¶meters )
222 const QMutexLocker locker( &
mMutex );
224 QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio, parameters, blocking );
225 return currentEntry->viewboxSize;
228void QgsSvgCache::containsParams(
const QString &path,
bool &hasFillParam, QColor &defaultFillColor,
bool &hasStrokeParam, QColor &defaultStrokeColor,
229 bool &hasStrokeWidthParam,
double &defaultStrokeWidth,
bool blocking )
const
231 bool hasDefaultFillColor =
false;
232 bool hasFillOpacityParam =
false;
233 bool hasDefaultFillOpacity =
false;
234 double defaultFillOpacity = 1.0;
235 bool hasDefaultStrokeColor =
false;
236 bool hasDefaultStrokeWidth =
false;
237 bool hasStrokeOpacityParam =
false;
238 bool hasDefaultStrokeOpacity =
false;
239 double defaultStrokeOpacity = 1.0;
241 containsParams( path, hasFillParam, hasDefaultFillColor, defaultFillColor,
242 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
243 hasStrokeParam, hasDefaultStrokeColor, defaultStrokeColor,
244 hasStrokeWidthParam, hasDefaultStrokeWidth, defaultStrokeWidth,
245 hasStrokeOpacityParam, hasDefaultStrokeOpacity, defaultStrokeOpacity,
250 bool &hasFillParam,
bool &hasDefaultFillParam, QColor &defaultFillColor,
251 bool &hasFillOpacityParam,
bool &hasDefaultFillOpacity,
double &defaultFillOpacity,
252 bool &hasStrokeParam,
bool &hasDefaultStrokeColor, QColor &defaultStrokeColor,
253 bool &hasStrokeWidthParam,
bool &hasDefaultStrokeWidth,
double &defaultStrokeWidth,
254 bool &hasStrokeOpacityParam,
bool &hasDefaultStrokeOpacity,
double &defaultStrokeOpacity,
255 bool blocking )
const
257 hasFillParam =
false;
258 hasFillOpacityParam =
false;
259 hasStrokeParam =
false;
260 hasStrokeWidthParam =
false;
261 hasStrokeOpacityParam =
false;
262 defaultFillColor = QColor( Qt::white );
263 defaultFillOpacity = 1.0;
264 defaultStrokeColor = QColor( Qt::black );
265 defaultStrokeWidth = 0.2;
266 defaultStrokeOpacity = 1.0;
268 hasDefaultFillParam =
false;
269 hasDefaultFillOpacity =
false;
270 hasDefaultStrokeColor =
false;
271 hasDefaultStrokeWidth =
false;
272 hasDefaultStrokeOpacity =
false;
275 if ( !svgDoc.setContent(
getContent( path, mMissingSvg, mFetchingSvg, blocking ) ) )
280 const QDomElement docElem = svgDoc.documentElement();
281 containsElemParams( docElem, hasFillParam, hasDefaultFillParam, defaultFillColor,
282 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
283 hasStrokeParam, hasDefaultStrokeColor, defaultStrokeColor,
284 hasStrokeWidthParam, hasDefaultStrokeWidth, defaultStrokeWidth,
285 hasStrokeOpacityParam, hasDefaultStrokeOpacity, defaultStrokeOpacity );
288void QgsSvgCache::replaceParamsAndCacheSvg( QgsSvgCacheEntry *entry,
bool blocking )
295 const QByteArray content =
getContent( entry->path, mMissingSvg, mFetchingSvg, blocking ) ;
296 entry->isMissingImage = content == mMissingSvg;
298 if ( !svgDoc.setContent( content ) )
304 QDomElement docElem = svgDoc.documentElement();
307 const double sizeScaleFactor = calcSizeScaleFactor( entry, docElem, viewboxSize );
308 entry->viewboxSize = viewboxSize;
309 replaceElemParams( docElem, entry->fill, entry->stroke, entry->strokeWidth * sizeScaleFactor, entry->parameters );
311 entry->svgContent = svgDoc.toByteArray( 0 );
316 entry->svgContent.replace(
"\n<tspan",
"<tspan" );
317 entry->svgContent.replace(
"</tspan>\n",
"</tspan>" );
322double QgsSvgCache::calcSizeScaleFactor( QgsSvgCacheEntry *entry,
const QDomElement &docElem, QSizeF &viewboxSize )
const
332 if ( docElem.tagName() == QLatin1String(
"svg" ) && docElem.hasAttribute( QStringLiteral(
"viewBox" ) ) )
334 viewBox = docElem.attribute( QStringLiteral(
"viewBox" ), QString() );
336 else if ( docElem.tagName() == QLatin1String(
"svg" ) && docElem.hasAttribute( QStringLiteral(
"viewbox" ) ) )
338 viewBox = docElem.attribute( QStringLiteral(
"viewbox" ), QString() );
342 const QDomElement svgElem = docElem.firstChildElement( QStringLiteral(
"svg" ) );
343 if ( !svgElem.isNull() )
345 if ( svgElem.hasAttribute( QStringLiteral(
"viewBox" ) ) )
346 viewBox = svgElem.attribute( QStringLiteral(
"viewBox" ), QString() );
347 else if ( svgElem.hasAttribute( QStringLiteral(
"viewbox" ) ) )
348 viewBox = svgElem.attribute( QStringLiteral(
"viewbox" ), QString() );
353 if ( viewBox.isEmpty() )
356 if ( docElem.tagName() == QLatin1String(
"svg" ) && docElem.hasAttribute( QStringLiteral(
"width" ) ) )
358 const QString widthString = docElem.attribute( QStringLiteral(
"width" ) );
359 const thread_local QRegularExpression measureRegEx( QStringLiteral(
"([\\d\\.]+).*?$" ) );
360 const QRegularExpressionMatch widthMatch = measureRegEx.match( widthString );
361 if ( widthMatch.hasMatch() )
363 const double width = widthMatch.captured( 1 ).toDouble();
364 const QString heightString = docElem.attribute( QStringLiteral(
"height" ) );
366 const QRegularExpressionMatch heightMatch = measureRegEx.match( heightString );
367 if ( heightMatch.hasMatch() )
369 const double height = heightMatch.captured( 1 ).toDouble();
370 viewboxSize = QSizeF( width, height );
371 return width / entry->size;
381 const QStringList parts = viewBox.split(
' ' );
382 if ( parts.count() != 4 )
385 bool heightOk =
false;
386 const double height = parts.at( 3 ).toDouble( &heightOk );
388 bool widthOk =
false;
389 const double width = parts.at( 2 ).toDouble( &widthOk );
393 viewboxSize = QSizeF( width, height );
394 return width / entry->size;
403 return getContent( path, mMissingSvg, mFetchingSvg, blocking );
410 const QString contentType = reply->header( QNetworkRequest::ContentTypeHeader ).toString();
411 if ( !contentType.startsWith( QLatin1String(
"image/svg+xml" ), Qt::CaseInsensitive )
412 && !contentType.startsWith( QLatin1String(
"text/plain" ), Qt::CaseInsensitive ) )
420void QgsSvgCache::cacheImage( QgsSvgCacheEntry *entry )
427 entry->image.reset();
431 const QSize imageSize = sizeForImage( *entry, viewBoxSize, scaledSize );
434 std::unique_ptr< QImage > image = std::make_unique< QImage >( imageSize, QImage::Format_ARGB32_Premultiplied );
437 const bool isFixedAR = entry->fixedAspectRatio > 0;
439 QPainter p( image.get() );
440 QSvgRenderer r( entry->svgContent );
441 if (
qgsDoubleNear( viewBoxSize.width(), viewBoxSize.height() ) )
447 QSizeF s( viewBoxSize );
448 s.scale( scaledSize.width(), scaledSize.height(), isFixedAR ? Qt::IgnoreAspectRatio : Qt::KeepAspectRatio );
449 const QRectF rect( ( imageSize.width() - s.width() ) / 2, ( imageSize.height() - s.height() ) / 2, s.width(), s.height() );
450 r.render( &p, rect );
453 mTotalSize += ( image->width() * image->height() * 32 );
454 entry->image = std::move( image );
457void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry,
bool forceVectorOutput )
459 Q_UNUSED( forceVectorOutput )
465 entry->picture.reset();
467 const bool isFixedAR = entry->fixedAspectRatio > 0;
470 std::unique_ptr< QPicture > picture = std::make_unique< QPicture >();
472 QSvgRenderer r( entry->svgContent );
473 double hwRatio = 1.0;
474 if ( r.viewBoxF().width() > 0 )
478 hwRatio = entry->fixedAspectRatio;
482 hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
486 const double wSize = entry->size;
487 const double hSize = wSize * hwRatio;
489 QSizeF s( r.viewBoxF().size() );
490 s.scale( wSize, hSize, isFixedAR ? Qt::IgnoreAspectRatio : Qt::KeepAspectRatio );
491 rect = QRectF( -s.width() / 2.0, -s.height() / 2.0, s.width(), s.height() );
493 QPainter p( picture.get() );
494 r.render( &p, rect );
495 entry->picture = std::move( picture );
499QgsSvgCacheEntry *QgsSvgCache::cacheEntry(
const QString &path,
double size,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
500 double widthScaleFactor,
double fixedAspectRatio,
const QMap<QString, QString> ¶meters,
bool blocking,
bool *isMissingImage )
502 QgsSvgCacheEntry *currentEntry =
findExistingEntry(
new QgsSvgCacheEntry( path, size, strokeWidth, widthScaleFactor, fill, stroke, fixedAspectRatio, parameters ) );
504 if ( currentEntry->svgContent.isEmpty() )
506 replaceParamsAndCacheSvg( currentEntry, blocking );
509 if ( isMissingImage )
510 *isMissingImage = currentEntry->isMissingImage;
516void QgsSvgCache::replaceElemParams( QDomElement &elem,
const QColor &fill,
const QColor &stroke,
double strokeWidth,
const QMap<QString, QString> ¶meters )
524 const QDomNamedNodeMap attributes = elem.attributes();
525 const int nAttributes = attributes.count();
526 for (
int i = 0; i < nAttributes; ++i )
528 const QDomAttr attribute = attributes.item( i ).toAttr();
530 if ( attribute.name().compare( QLatin1String(
"style" ), Qt::CaseInsensitive ) == 0 )
533 QString newAttributeString;
535 const QStringList entryList = attribute.value().split(
';' );
536 QStringList::const_iterator entryIt = entryList.constBegin();
537 for ( ; entryIt != entryList.constEnd(); ++entryIt )
539 const QStringList keyValueSplit = entryIt->split(
':' );
540 if ( keyValueSplit.size() < 2 )
544 const QString key = keyValueSplit.at( 0 );
545 QString value = keyValueSplit.at( 1 );
546 QString newValue = value;
547 value = value.trimmed().toLower();
549 if ( value.startsWith( QLatin1String(
"param(fill)" ) ) )
551 newValue = fill.name();
553 else if ( value.startsWith( QLatin1String(
"param(fill-opacity)" ) ) )
555 newValue = QString::number( fill.alphaF() );
557 else if ( value.startsWith( QLatin1String(
"param(outline)" ) ) )
559 newValue = stroke.name();
561 else if ( value.startsWith( QLatin1String(
"param(outline-opacity)" ) ) )
563 newValue = QString::number( stroke.alphaF() );
565 else if ( value.startsWith( QLatin1String(
"param(outline-width)" ) ) )
567 newValue = QString::number( strokeWidth );
570 if ( entryIt != entryList.constBegin() )
572 newAttributeString.append(
';' );
574 newAttributeString.append( key +
':' + newValue );
576 elem.setAttribute( attribute.name(), newAttributeString );
580 const QString value = attribute.value().trimmed().toLower();
581 if ( value.startsWith( QLatin1String(
"param(fill)" ) ) )
583 elem.setAttribute( attribute.name(), fill.name() );
585 else if ( value.startsWith( QLatin1String(
"param(fill-opacity)" ) ) )
587 elem.setAttribute( attribute.name(), fill.alphaF() );
589 else if ( value.startsWith( QLatin1String(
"param(outline)" ) ) )
591 elem.setAttribute( attribute.name(), stroke.name() );
593 else if ( value.startsWith( QLatin1String(
"param(outline-opacity)" ) ) )
595 elem.setAttribute( attribute.name(), stroke.alphaF() );
597 else if ( value.startsWith( QLatin1String(
"param(outline-width)" ) ) )
599 elem.setAttribute( attribute.name(), QString::number( strokeWidth ) );
603 QMap<QString, QString>::const_iterator paramIt = parameters.constBegin();
604 for ( ; paramIt != parameters.constEnd(); ++paramIt )
606 if ( value.startsWith( QString( QLatin1String(
"param(%1)" ) ).arg( paramIt.key() ) ) )
608 elem.setAttribute( attribute.name(), paramIt.value() );
616 QDomNode child = elem.firstChild();
617 if ( child.isText() && child.nodeValue().startsWith(
"param(" ) )
619 QMap<QString, QString>::const_iterator paramIt = parameters.constBegin();
620 for ( ; paramIt != parameters.constEnd(); ++paramIt )
622 if ( child.toText().data().startsWith( QString( QLatin1String(
"param(%1)" ) ).arg( paramIt.key() ) ) )
624 child.setNodeValue( paramIt.value() );
630 const QDomNodeList childList = elem.childNodes();
631 const int nChildren = childList.count();
632 for (
int i = 0; i < nChildren; ++i )
634 QDomElement childElem = childList.at( i ).toElement();
635 replaceElemParams( childElem, fill, stroke, strokeWidth, parameters );
639void QgsSvgCache::containsElemParams(
const QDomElement &elem,
bool &hasFillParam,
bool &hasDefaultFill, QColor &defaultFill,
640 bool &hasFillOpacityParam,
bool &hasDefaultFillOpacity,
double &defaultFillOpacity,
641 bool &hasStrokeParam,
bool &hasDefaultStroke, QColor &defaultStroke,
642 bool &hasStrokeWidthParam,
bool &hasDefaultStrokeWidth,
double &defaultStrokeWidth,
643 bool &hasStrokeOpacityParam,
bool &hasDefaultStrokeOpacity,
double &defaultStrokeOpacity )
const
651 if ( hasFillParam && hasStrokeParam && hasStrokeWidthParam && hasFillOpacityParam && hasStrokeOpacityParam )
657 const QDomNamedNodeMap attributes = elem.attributes();
658 const int nAttributes = attributes.count();
660 QStringList valueSplit;
661 for (
int i = 0; i < nAttributes; ++i )
663 const QDomAttr attribute = attributes.item( i ).toAttr();
664 if ( attribute.name().compare( QLatin1String(
"style" ), Qt::CaseInsensitive ) == 0 )
667 const QStringList entryList = attribute.value().split(
';' );
668 QStringList::const_iterator entryIt = entryList.constBegin();
669 for ( ; entryIt != entryList.constEnd(); ++entryIt )
671 const QStringList keyValueSplit = entryIt->split(
':' );
672 if ( keyValueSplit.size() < 2 )
676 const QString value = keyValueSplit.at( 1 );
677 valueSplit = value.split(
' ' );
678 if ( !hasFillParam && value.startsWith( QLatin1String(
"param(fill)" ) ) )
681 if ( valueSplit.size() > 1 )
683 defaultFill = QColor( valueSplit.at( 1 ) );
684 hasDefaultFill =
true;
687 else if ( !hasFillOpacityParam && value.startsWith( QLatin1String(
"param(fill-opacity)" ) ) )
689 hasFillOpacityParam =
true;
690 if ( valueSplit.size() > 1 )
693 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
696 defaultFillOpacity = opacity;
697 hasDefaultFillOpacity =
true;
701 else if ( !hasStrokeParam && value.startsWith( QLatin1String(
"param(outline)" ) ) )
703 hasStrokeParam =
true;
704 if ( valueSplit.size() > 1 )
706 defaultStroke = QColor( valueSplit.at( 1 ) );
707 hasDefaultStroke =
true;
710 else if ( !hasStrokeWidthParam && value.startsWith( QLatin1String(
"param(outline-width)" ) ) )
712 hasStrokeWidthParam =
true;
713 if ( valueSplit.size() > 1 )
715 defaultStrokeWidth = valueSplit.at( 1 ).toDouble();
716 hasDefaultStrokeWidth =
true;
719 else if ( !hasStrokeOpacityParam && value.startsWith( QLatin1String(
"param(outline-opacity)" ) ) )
721 hasStrokeOpacityParam =
true;
722 if ( valueSplit.size() > 1 )
725 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
728 defaultStrokeOpacity = opacity;
729 hasDefaultStrokeOpacity =
true;
737 const QString value = attribute.value();
738 valueSplit = value.split(
' ' );
739 if ( !hasFillParam && value.startsWith( QLatin1String(
"param(fill)" ) ) )
742 if ( valueSplit.size() > 1 )
744 defaultFill = QColor( valueSplit.at( 1 ) );
745 hasDefaultFill =
true;
748 else if ( !hasFillOpacityParam && value.startsWith( QLatin1String(
"param(fill-opacity)" ) ) )
750 hasFillOpacityParam =
true;
751 if ( valueSplit.size() > 1 )
754 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
757 defaultFillOpacity = opacity;
758 hasDefaultFillOpacity =
true;
762 else if ( !hasStrokeParam && value.startsWith( QLatin1String(
"param(outline)" ) ) )
764 hasStrokeParam =
true;
765 if ( valueSplit.size() > 1 )
767 defaultStroke = QColor( valueSplit.at( 1 ) );
768 hasDefaultStroke =
true;
771 else if ( !hasStrokeWidthParam && value.startsWith( QLatin1String(
"param(outline-width)" ) ) )
773 hasStrokeWidthParam =
true;
774 if ( valueSplit.size() > 1 )
776 defaultStrokeWidth = valueSplit.at( 1 ).toDouble();
777 hasDefaultStrokeWidth =
true;
780 else if ( !hasStrokeOpacityParam && value.startsWith( QLatin1String(
"param(outline-opacity)" ) ) )
782 hasStrokeOpacityParam =
true;
783 if ( valueSplit.size() > 1 )
786 const double opacity = valueSplit.at( 1 ).toDouble( &ok );
789 defaultStrokeOpacity = opacity;
790 hasDefaultStrokeOpacity =
true;
798 const QDomNodeList childList = elem.childNodes();
799 const int nChildren = childList.count();
800 for (
int i = 0; i < nChildren; ++i )
802 const QDomElement childElem = childList.at( i ).toElement();
803 containsElemParams( childElem, hasFillParam, hasDefaultFill, defaultFill,
804 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
805 hasStrokeParam, hasDefaultStroke, defaultStroke,
806 hasStrokeWidthParam, hasDefaultStrokeWidth, defaultStrokeWidth,
807 hasStrokeOpacityParam, hasDefaultStrokeOpacity, defaultStrokeOpacity );
811QSize QgsSvgCache::sizeForImage(
const QgsSvgCacheEntry &entry, QSizeF &viewBoxSize, QSizeF &scaledSize )
const
813 const bool isFixedAR = entry.fixedAspectRatio > 0;
815 const QSvgRenderer r( entry.svgContent );
816 double hwRatio = 1.0;
817 viewBoxSize = r.viewBoxF().size();
818 if ( viewBoxSize.width() > 0 )
822 hwRatio = entry.fixedAspectRatio;
826 hwRatio = viewBoxSize.height() / viewBoxSize.width();
831 scaledSize.setWidth( entry.size );
832 int wImgSize =
static_cast< int >( scaledSize.width() );
837 scaledSize.setHeight( scaledSize.width() * hwRatio );
838 int hImgSize =
static_cast< int >( scaledSize.height() );
843 return QSize( wImgSize, hImgSize );
846QImage QgsSvgCache::imageFromCachedPicture(
const QgsSvgCacheEntry &entry )
const
850 QImage image( sizeForImage( entry, viewBoxSize, scaledSize ), QImage::Format_ARGB32_Premultiplied );
853 QPainter p( &image );
854 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)