25 #include <QApplication> 26 #include <QCoreApplication> 28 #include <QDomDocument> 29 #include <QDomElement> 34 #include <QSvgRenderer> 36 #include <QNetworkReply> 37 #include <QNetworkRequest> 43 , widthScaleFactor( 1.0 )
44 , rasterScaleFactor( 1.0 )
46 , outline(
Qt::black )
49 , nextEntry( nullptr )
50 , previousEntry( nullptr )
106 , mLeastRecentEntry( nullptr )
107 , mMostRecentEntry( nullptr )
109 mMissingSvg =
QString(
"<svg width='10' height='10'><text x='5' y='10' font-size='10' text-anchor='middle'>?</text></svg>" ).
toAscii();
114 qDeleteAll( mEntryLookup );
119 double widthScaleFactor,
double rasterScaleFactor,
bool& fitsInCache )
129 if ( !currentEntry->
image )
132 double hwRatio = 1.0;
137 long cachedDataSize = 0;
139 cachedDataSize +=
static_cast< int >( currentEntry->
size * currentEntry->
size * hwRatio * 32 );
140 if ( cachedDataSize > mMaximumSize / 2 )
143 delete currentEntry->
image;
144 currentEntry->
image =
nullptr;
160 return *( currentEntry->
image );
164 double widthScaleFactor,
double rasterScaleFactor,
bool forceVectorOutput )
178 return *( currentEntry->
picture );
182 double widthScaleFactor,
double rasterScaleFactor )
201 double widthScaleFactor,
double rasterScaleFactor )
210 mEntryLookup.
insert( file, entry );
213 if ( !mMostRecentEntry )
215 mLeastRecentEntry = entry;
216 mMostRecentEntry = entry;
225 mMostRecentEntry = entry;
233 bool& hasOutlineWidthParam,
double& defaultOutlineWidth )
const 235 bool hasDefaultFillColor =
false;
236 bool hasFillOpacityParam =
false;
237 bool hasDefaultFillOpacity =
false;
238 double defaultFillOpacity = 1.0;
239 bool hasDefaultOutlineColor =
false;
240 bool hasDefaultOutlineWidth =
false;
241 bool hasOutlineOpacityParam =
false;
242 bool hasDefaultOutlineOpacity =
false;
243 double defaultOutlineOpacity = 1.0;
245 containsParams( path, hasFillParam, hasDefaultFillColor, defaultFillColor,
246 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
247 hasOutlineParam, hasDefaultOutlineColor, defaultOutlineColor,
248 hasOutlineWidthParam, hasDefaultOutlineWidth, defaultOutlineWidth,
249 hasOutlineOpacityParam, hasDefaultOutlineOpacity, defaultOutlineOpacity );
254 bool& hasFillParam,
bool& hasDefaultFillParam,
QColor& defaultFillColor,
255 bool& hasOutlineParam,
bool& hasDefaultOutlineColor,
QColor& defaultOutlineColor,
256 bool& hasOutlineWidthParam,
bool& hasDefaultOutlineWidth,
double& defaultOutlineWidth )
const 258 bool hasFillOpacityParam =
false;
259 bool hasDefaultFillOpacity =
false;
260 double defaultFillOpacity = 1.0;
261 bool hasOutlineOpacityParam =
false;
262 bool hasDefaultOutlineOpacity =
false;
263 double defaultOutlineOpacity = 1.0;
265 containsParams( path, hasFillParam, hasDefaultFillParam, defaultFillColor,
266 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
267 hasOutlineParam, hasDefaultOutlineColor, defaultOutlineColor,
268 hasOutlineWidthParam, hasDefaultOutlineWidth, defaultOutlineWidth,
269 hasOutlineOpacityParam, hasDefaultOutlineOpacity, defaultOutlineOpacity );
273 bool& hasFillParam,
bool& hasDefaultFillParam,
QColor& defaultFillColor,
274 bool& hasFillOpacityParam,
bool& hasDefaultFillOpacity,
double& defaultFillOpacity,
275 bool& hasOutlineParam,
bool& hasDefaultOutlineColor,
QColor& defaultOutlineColor,
276 bool& hasOutlineWidthParam,
bool& hasDefaultOutlineWidth,
double& defaultOutlineWidth,
277 bool& hasOutlineOpacityParam,
bool& hasDefaultOutlineOpacity,
double& defaultOutlineOpacity )
const 279 hasFillParam =
false;
280 hasFillOpacityParam =
false;
281 hasOutlineParam =
false;
282 hasOutlineWidthParam =
false;
283 hasOutlineOpacityParam =
false;
284 defaultFillColor =
QColor( Qt::white );
285 defaultFillOpacity = 1.0;
286 defaultOutlineColor =
QColor( Qt::black );
287 defaultOutlineWidth = 0.2;
288 defaultOutlineOpacity = 1.0;
290 hasDefaultFillParam =
false;
291 hasDefaultFillOpacity =
false;
292 hasDefaultOutlineColor =
false;
293 hasDefaultOutlineWidth =
false;
294 hasDefaultOutlineOpacity =
false;
303 containsElemParams( docElem, hasFillParam, hasDefaultFillParam, defaultFillColor,
304 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
305 hasOutlineParam, hasDefaultOutlineColor, defaultOutlineColor,
306 hasOutlineWidthParam, hasDefaultOutlineWidth, defaultOutlineWidth,
307 hasOutlineOpacityParam, hasDefaultOutlineOpacity, defaultOutlineOpacity );
327 double sizeScaleFactor = calcSizeScaleFactor( entry, docElem, viewboxSize );
377 if ( parts.
count() != 4 )
380 bool heightOk =
false;
381 double height = parts.
at( 3 ).toDouble( &heightOk );
383 bool widthOk =
false;
384 double width = parts.
at( 2 ).toDouble( &widthOk );
388 viewboxSize =
QSizeF( width, height );
389 return width / entry->
size;
398 QFile svgFile( path );
401 if ( svgFile.
open( QIODevice::ReadOnly ) )
424 if ( svgUrl.
scheme().
compare(
"file", Qt::CaseInsensitive ) == 0 )
429 if ( svgFile.
open( QIODevice::ReadOnly ) )
449 request.
setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
450 request.
setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
453 connect( reply, SIGNAL( downloadProgress( qint64, qint64 ) ),
this, SLOT( downloadProgress( qint64, qint64 ) ) );
464 if ( reply->
error() != QNetworkReply::NoError )
472 QVariant redirect = reply->
attribute( QNetworkRequest::RedirectionTargetAttribute );
481 svgUrl = redirect.
toUrl();
488 QVariant phrase = reply->
attribute( QNetworkRequest::HttpReasonPhraseAttribute );
497 if ( !contentType.
startsWith(
"image/svg+xml", Qt::CaseInsensitive ) )
518 entry->
image =
nullptr;
521 double hwRatio = 1.0;
526 double wSize = entry->
size;
527 int wImgSize =
static_cast< int >( wSize );
532 double hSize = wSize * hwRatio;
533 int hImgSize =
static_cast< int >( hSize );
539 QImage* image =
new QImage( wImgSize, hImgSize, QImage::Format_ARGB32_Premultiplied );
550 s.
scale( wSize, hSize, Qt::KeepAspectRatio );
551 QRectF rect(( wImgSize - s.width() ) / 2, ( hImgSize - s.height() ) / 2, s.width(), s.height() );
555 entry->
image = image;
556 mTotalSize += ( image->
width() * image->
height() * 32 );
561 Q_UNUSED( forceVectorOutput );
574 double hwRatio = 1.0;
580 double wSize = entry->
size;
581 double hSize = wSize * hwRatio;
583 s.
scale( wSize, hSize, Qt::KeepAspectRatio );
584 rect =
QRectF( -s.width() / 2.0, -s.height() / 2.0, s.width(), s.height() );
593 double widthScaleFactor,
double rasterScaleFactor )
600 for ( ; entryIt != entries.
end(); ++entryIt )
616 currentEntry =
insertSVG( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor );
621 if ( !mMostRecentEntry )
623 mMostRecentEntry = currentEntry;
624 mLeastRecentEntry = currentEntry;
628 mMostRecentEntry->
nextEntry = currentEntry;
631 mMostRecentEntry = currentEntry;
641 void QgsSvgCache::replaceElemParams(
QDomElement& elem,
const QColor& fill,
const QColor& outline,
double outlineWidth )
650 int nAttributes = attributes.
count();
651 for (
int i = 0; i < nAttributes; ++i )
655 if ( attribute.
name().
compare(
"style", Qt::CaseInsensitive ) == 0 )
662 for ( ; entryIt != entryList.
constEnd(); ++entryIt )
665 if ( keyValueSplit.
size() < 2 )
675 else if ( value.
startsWith(
"param(fill-opacity)" ) )
679 else if ( value.
startsWith(
"param(outline)" ) )
681 value = outline.
name();
683 else if ( value.
startsWith(
"param(outline-opacity)" ) )
687 else if ( value.
startsWith(
"param(outline-width)" ) )
694 newAttributeString.
append(
';' );
696 newAttributeString.
append( key +
':' + value );
707 else if ( value.
startsWith(
"param(fill-opacity)" ) )
711 else if ( value.
startsWith(
"param(outline)" ) )
715 else if ( value.
startsWith(
"param(outline-opacity)" ) )
719 else if ( value.
startsWith(
"param(outline-width)" ) )
727 int nChildren = childList.
count();
728 for (
int i = 0; i < nChildren; ++i )
731 replaceElemParams( childElem, fill, outline, outlineWidth );
735 void QgsSvgCache::containsElemParams(
const QDomElement& elem,
bool& hasFillParam,
bool& hasDefaultFill,
QColor& defaultFill,
736 bool& hasFillOpacityParam,
bool& hasDefaultFillOpacity,
double& defaultFillOpacity,
737 bool& hasOutlineParam,
bool& hasDefaultOutline,
QColor& defaultOutline,
738 bool& hasOutlineWidthParam,
bool& hasDefaultOutlineWidth,
double& defaultOutlineWidth,
739 bool& hasOutlineOpacityParam,
bool& hasDefaultOutlineOpacity,
double& defaultOutlineOpacity )
const 747 if ( hasFillParam && hasOutlineParam && hasOutlineWidthParam && hasFillOpacityParam && hasOutlineOpacityParam )
754 int nAttributes = attributes.
count();
757 for (
int i = 0; i < nAttributes; ++i )
760 if ( attribute.
name().
compare(
"style", Qt::CaseInsensitive ) == 0 )
765 for ( ; entryIt != entryList.
constEnd(); ++entryIt )
768 if ( keyValueSplit.
size() < 2 )
774 valueSplit = value.
split(
' ' );
775 if ( !hasFillParam && value.
startsWith(
"param(fill)" ) )
778 if ( valueSplit.
size() > 1 )
780 defaultFill =
QColor( valueSplit.
at( 1 ) );
781 hasDefaultFill =
true;
784 else if ( !hasFillOpacityParam && value.
startsWith(
"param(fill-opacity)" ) )
786 hasFillOpacityParam =
true;
787 if ( valueSplit.
size() > 1 )
790 double opacity = valueSplit.
at( 1 ).toDouble( &ok );
793 defaultFillOpacity = opacity;
794 hasDefaultFillOpacity =
true;
798 else if ( !hasOutlineParam && value.
startsWith(
"param(outline)" ) )
800 hasOutlineParam =
true;
801 if ( valueSplit.
size() > 1 )
803 defaultOutline =
QColor( valueSplit.
at( 1 ) );
804 hasDefaultOutline =
true;
807 else if ( !hasOutlineWidthParam && value.
startsWith(
"param(outline-width)" ) )
809 hasOutlineWidthParam =
true;
810 if ( valueSplit.
size() > 1 )
812 defaultOutlineWidth = valueSplit.
at( 1 ).toDouble();
813 hasDefaultOutlineWidth =
true;
816 else if ( !hasOutlineOpacityParam && value.
startsWith(
"param(outline-opacity)" ) )
818 hasOutlineOpacityParam =
true;
819 if ( valueSplit.
size() > 1 )
822 double opacity = valueSplit.
at( 1 ).toDouble( &ok );
825 defaultOutlineOpacity = opacity;
826 hasDefaultOutlineOpacity =
true;
835 valueSplit = value.
split(
' ' );
836 if ( !hasFillParam && value.
startsWith(
"param(fill)" ) )
839 if ( valueSplit.
size() > 1 )
841 defaultFill =
QColor( valueSplit.
at( 1 ) );
842 hasDefaultFill =
true;
845 else if ( !hasFillOpacityParam && value.
startsWith(
"param(fill-opacity)" ) )
847 hasFillOpacityParam =
true;
848 if ( valueSplit.
size() > 1 )
851 double opacity = valueSplit.
at( 1 ).toDouble( &ok );
854 defaultFillOpacity = opacity;
855 hasDefaultFillOpacity =
true;
859 else if ( !hasOutlineParam && value.
startsWith(
"param(outline)" ) )
861 hasOutlineParam =
true;
862 if ( valueSplit.
size() > 1 )
864 defaultOutline =
QColor( valueSplit.
at( 1 ) );
865 hasDefaultOutline =
true;
868 else if ( !hasOutlineWidthParam && value.
startsWith(
"param(outline-width)" ) )
870 hasOutlineWidthParam =
true;
871 if ( valueSplit.
size() > 1 )
873 defaultOutlineWidth = valueSplit.
at( 1 ).toDouble();
874 hasDefaultOutlineWidth =
true;
877 else if ( !hasOutlineOpacityParam && value.
startsWith(
"param(outline-opacity)" ) )
879 hasOutlineOpacityParam =
true;
880 if ( valueSplit.
size() > 1 )
883 double opacity = valueSplit.
at( 1 ).toDouble( &ok );
886 defaultOutlineOpacity = opacity;
887 hasDefaultOutlineOpacity =
true;
896 int nChildren = childList.
count();
897 for (
int i = 0; i < nChildren; ++i )
900 containsElemParams( childElem, hasFillParam, hasDefaultFill, defaultFill,
901 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
902 hasOutlineParam, hasDefaultOutline, defaultOutline,
903 hasOutlineWidthParam, hasDefaultOutlineWidth, defaultOutlineWidth,
904 hasOutlineOpacityParam, hasDefaultOutlineOpacity, defaultOutlineOpacity );
911 mEntryLookup.
remove( s, entry );
914 void QgsSvgCache::printEntryList()
916 QgsDebugMsg(
"****************svg cache entry list*************************" );
933 if ( mLeastRecentEntry == mMostRecentEntry )
938 while ( entry && ( mTotalSize > mMaximumSize ) )
975 void QgsSvgCache::downloadProgress( qint64 bytesReceived, qint64 bytesTotal )
QgsSvgCacheEntry * previousEntry
QString & append(QChar ch)
QSizeF viewboxSize
SVG viewbox size.
void scale(qreal width, qreal height, Qt::AspectRatioMode mode)
QByteArray getImageData(const QString &path) const
Get image data.
void render(QPainter *painter)
const QPicture & svgAsPicture(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor, bool forceVectorOutput=false)
Get SVG as QPicture&.
QSizeF svgViewboxSize(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor)
Calculates the viewbox size of a (possibly cached) SVG file.
QString attribute(const QString &name, const QString &defValue) const
QString errorString() const
QgsSvgCacheEntry * cacheEntry(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor)
Returns entry from cache or creates a new entry if it does not exist already.
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
const T & at(int i) const
A cache for images / pictures derived from svg files.
void setFileName(const QString &name)
void containsParams(const QString &path, bool &hasFillParam, QColor &defaultFillColor, bool &hasOutlineParam, QColor &defaultOutlineColor, bool &hasOutlineWidthParam, double &defaultOutlineWidth) const
Tests if an svg file contains parameters for fill, outline color, outline width.
QDomElement documentElement() const
QDomNodeList childNodes() const
QString toString(QFlags< QUrl::FormattingOption > options) const
QString tr(const char *sourceText, const char *disambiguation, int n)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
static QgsSvgCache * instance()
QDomElement toElement() const
const QImage & svgAsImage(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor, bool &fitsInCache)
Get SVG as QImage.
int dataSize() const
Return memory usage in bytes.
QString number(int n, int base)
int count(const T &value) const
void processEvents(QFlags< QEventLoop::ProcessEventsFlag > flags)
int toInt(bool *ok) const
void fill(uint pixelValue)
bool hasAttribute(const QString &name) const
void setAttribute(const QString &name, const QString &value)
int remove(const Key &key)
static QString symbolNameToPath(QString name)
Get symbol's path from its name.
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
QByteArray & replace(int pos, int len, const char *after)
static void logMessage(const QString &message, const QString &tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
void statusChanged(const QString &theStatusQString)
Emit a signal to be caught by qgisapp and display a msg on status bar.
QgsSvgCache(QObject *parent=nullptr)
protected constructor
const QByteArray & svgContent(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor)
Get SVG content.
void cachePicture(QgsSvgCacheEntry *entry, bool forceVectorOutput=false)
QHash< Key, T >::iterator insert(const Key &key, const T &value)
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
QString toLocalFile() const
bool contains(QChar ch, Qt::CaseSensitivity cs) const
void trimToMaximumSize()
Removes the least used items until the maximum size is under the limit.
void takeEntryFromList(QgsSvgCacheEntry *entry)
QString lookupKey
Lookup key used by QgsSvgCache's hashtable (relative or absolute path). Needed for removal from the h...
void cacheImage(QgsSvgCacheEntry *entry)
void replaceParamsAndCacheSvg(QgsSvgCacheEntry *entry)
static QgsNetworkAccessManager * instance()
returns a pointer to the single instance
QDomElement firstChildElement(const QString &tagName) const
QVariant attribute(QNetworkRequest::Attribute code) const
void setAttribute(Attribute code, const QVariant &value)
QgsSvgCacheEntry * insertSVG(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor)
Creates new cache entry and returns pointer to it.
NetworkError error() const
QNetworkReply * get(const QNetworkRequest &request)
const_iterator constEnd() const
const_iterator constBegin() const
QDomNode item(int index) const
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
int compare(const QString &other) const
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
bool operator==(const QgsSvgCacheEntry &other) const
Don't consider image, picture, last used timestamp for comparison.
QString file
Absolute path to SVG file.
QByteArray toAscii() const
QByteArray toByteArray(int indent) const
QDomNode at(int index) const
bool setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn)
QgsSvgCacheEntry * nextEntry
QDomNamedNodeMap attributes() const