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 );
345 if ( docElem.
tagName() ==
"svg" )
364 if ( parts.
count() != 4 )
367 bool heightOk =
false;
368 double height = parts.
at( 3 ).toDouble( &heightOk );
370 bool widthOk =
false;
371 double width = parts.
at( 2 ).toDouble( &widthOk );
375 viewboxSize =
QSizeF( width, height );
376 return width / entry->
size;
385 QFile svgFile( path );
388 if ( svgFile.
open( QIODevice::ReadOnly ) )
411 if ( svgUrl.
scheme().
compare(
"file", Qt::CaseInsensitive ) == 0 )
416 if ( svgFile.
open( QIODevice::ReadOnly ) )
436 request.
setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
437 request.
setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
440 connect( reply, SIGNAL( downloadProgress( qint64, qint64 ) ),
this, SLOT( downloadProgress( qint64, qint64 ) ) );
451 if ( reply->
error() != QNetworkReply::NoError )
459 QVariant redirect = reply->
attribute( QNetworkRequest::RedirectionTargetAttribute );
468 svgUrl = redirect.
toUrl();
475 QVariant phrase = reply->
attribute( QNetworkRequest::HttpReasonPhraseAttribute );
484 if ( !contentType.
startsWith(
"image/svg+xml", Qt::CaseInsensitive ) )
505 entry->
image =
nullptr;
508 double hwRatio = 1.0;
513 double wSize = entry->
size;
514 int wImgSize =
static_cast< int >( wSize );
519 double hSize = wSize * hwRatio;
520 int hImgSize =
static_cast< int >( hSize );
526 QImage* image =
new QImage( wImgSize, hImgSize, QImage::Format_ARGB32_Premultiplied );
537 s.
scale( wSize, hSize, Qt::KeepAspectRatio );
538 QRectF rect(( wImgSize - s.width() ) / 2, ( hImgSize - s.height() ) / 2, s.width(), s.height() );
542 entry->
image = image;
543 mTotalSize += ( image->
width() * image->
height() * 32 );
548 Q_UNUSED( forceVectorOutput );
561 double hwRatio = 1.0;
567 double wSize = entry->
size;
568 double hSize = wSize * hwRatio;
570 s.
scale( wSize, hSize, Qt::KeepAspectRatio );
571 rect =
QRectF( -s.width() / 2.0, -s.height() / 2.0, s.width(), s.height() );
580 double widthScaleFactor,
double rasterScaleFactor )
587 for ( ; entryIt != entries.
end(); ++entryIt )
603 currentEntry =
insertSVG( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor );
608 if ( !mMostRecentEntry )
610 mMostRecentEntry = currentEntry;
611 mLeastRecentEntry = currentEntry;
615 mMostRecentEntry->
nextEntry = currentEntry;
618 mMostRecentEntry = currentEntry;
628 void QgsSvgCache::replaceElemParams(
QDomElement& elem,
const QColor& fill,
const QColor& outline,
double outlineWidth )
637 int nAttributes = attributes.
count();
638 for (
int i = 0; i < nAttributes; ++i )
642 if ( attribute.
name().
compare(
"style", Qt::CaseInsensitive ) == 0 )
649 for ( ; entryIt != entryList.
constEnd(); ++entryIt )
652 if ( keyValueSplit.
size() < 2 )
662 else if ( value.
startsWith(
"param(fill-opacity)" ) )
666 else if ( value.
startsWith(
"param(outline)" ) )
668 value = outline.
name();
670 else if ( value.
startsWith(
"param(outline-opacity)" ) )
674 else if ( value.
startsWith(
"param(outline-width)" ) )
681 newAttributeString.
append(
';' );
683 newAttributeString.
append( key +
':' + value );
694 else if ( value.
startsWith(
"param(fill-opacity)" ) )
698 else if ( value.
startsWith(
"param(outline)" ) )
702 else if ( value.
startsWith(
"param(outline-opacity)" ) )
706 else if ( value.
startsWith(
"param(outline-width)" ) )
714 int nChildren = childList.
count();
715 for (
int i = 0; i < nChildren; ++i )
718 replaceElemParams( childElem, fill, outline, outlineWidth );
722 void QgsSvgCache::containsElemParams(
const QDomElement& elem,
bool& hasFillParam,
bool& hasDefaultFill,
QColor& defaultFill,
723 bool& hasFillOpacityParam,
bool& hasDefaultFillOpacity,
double& defaultFillOpacity,
724 bool& hasOutlineParam,
bool& hasDefaultOutline,
QColor& defaultOutline,
725 bool& hasOutlineWidthParam,
bool& hasDefaultOutlineWidth,
double& defaultOutlineWidth,
726 bool& hasOutlineOpacityParam,
bool& hasDefaultOutlineOpacity,
double& defaultOutlineOpacity )
const 734 if ( hasFillParam && hasOutlineParam && hasOutlineWidthParam && hasFillOpacityParam && hasOutlineOpacityParam )
741 int nAttributes = attributes.
count();
744 for (
int i = 0; i < nAttributes; ++i )
747 if ( attribute.
name().
compare(
"style", Qt::CaseInsensitive ) == 0 )
752 for ( ; entryIt != entryList.
constEnd(); ++entryIt )
755 if ( keyValueSplit.
size() < 2 )
761 valueSplit = value.
split(
' ' );
762 if ( !hasFillParam && value.
startsWith(
"param(fill)" ) )
765 if ( valueSplit.
size() > 1 )
767 defaultFill =
QColor( valueSplit.
at( 1 ) );
768 hasDefaultFill =
true;
771 else if ( !hasFillOpacityParam && value.
startsWith(
"param(fill-opacity)" ) )
773 hasFillOpacityParam =
true;
774 if ( valueSplit.
size() > 1 )
777 double opacity = valueSplit.
at( 1 ).toDouble( &ok );
780 defaultFillOpacity = opacity;
781 hasDefaultFillOpacity =
true;
785 else if ( !hasOutlineParam && value.
startsWith(
"param(outline)" ) )
787 hasOutlineParam =
true;
788 if ( valueSplit.
size() > 1 )
790 defaultOutline =
QColor( valueSplit.
at( 1 ) );
791 hasDefaultOutline =
true;
794 else if ( !hasOutlineWidthParam && value.
startsWith(
"param(outline-width)" ) )
796 hasOutlineWidthParam =
true;
797 if ( valueSplit.
size() > 1 )
799 defaultOutlineWidth = valueSplit.
at( 1 ).toDouble();
800 hasDefaultOutlineWidth =
true;
803 else if ( !hasOutlineOpacityParam && value.
startsWith(
"param(outline-opacity)" ) )
805 hasOutlineOpacityParam =
true;
806 if ( valueSplit.
size() > 1 )
809 double opacity = valueSplit.
at( 1 ).toDouble( &ok );
812 defaultOutlineOpacity = opacity;
813 hasDefaultOutlineOpacity =
true;
822 valueSplit = value.
split(
' ' );
823 if ( !hasFillParam && value.
startsWith(
"param(fill)" ) )
826 if ( valueSplit.
size() > 1 )
828 defaultFill =
QColor( valueSplit.
at( 1 ) );
829 hasDefaultFill =
true;
832 else if ( !hasFillOpacityParam && value.
startsWith(
"param(fill-opacity)" ) )
834 hasFillOpacityParam =
true;
835 if ( valueSplit.
size() > 1 )
838 double opacity = valueSplit.
at( 1 ).toDouble( &ok );
841 defaultFillOpacity = opacity;
842 hasDefaultFillOpacity =
true;
846 else if ( !hasOutlineParam && value.
startsWith(
"param(outline)" ) )
848 hasOutlineParam =
true;
849 if ( valueSplit.
size() > 1 )
851 defaultOutline =
QColor( valueSplit.
at( 1 ) );
852 hasDefaultOutline =
true;
855 else if ( !hasOutlineWidthParam && value.
startsWith(
"param(outline-width)" ) )
857 hasOutlineWidthParam =
true;
858 if ( valueSplit.
size() > 1 )
860 defaultOutlineWidth = valueSplit.
at( 1 ).toDouble();
861 hasDefaultOutlineWidth =
true;
864 else if ( !hasOutlineOpacityParam && value.
startsWith(
"param(outline-opacity)" ) )
866 hasOutlineOpacityParam =
true;
867 if ( valueSplit.
size() > 1 )
870 double opacity = valueSplit.
at( 1 ).toDouble( &ok );
873 defaultOutlineOpacity = opacity;
874 hasDefaultOutlineOpacity =
true;
883 int nChildren = childList.
count();
884 for (
int i = 0; i < nChildren; ++i )
887 containsElemParams( childElem, hasFillParam, hasDefaultFill, defaultFill,
888 hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
889 hasOutlineParam, hasDefaultOutline, defaultOutline,
890 hasOutlineWidthParam, hasDefaultOutlineWidth, defaultOutlineWidth,
891 hasOutlineOpacityParam, hasDefaultOutlineOpacity, defaultOutlineOpacity );
898 mEntryLookup.
remove( s, entry );
901 void QgsSvgCache::printEntryList()
903 QgsDebugMsg(
"****************svg cache entry list*************************" );
920 if ( mLeastRecentEntry == mMostRecentEntry )
925 while ( entry && ( mTotalSize > mMaximumSize ) )
962 void QgsSvgCache::downloadProgress( qint64 bytesReceived, qint64 bytesTotal )
QgsSvgCacheEntry * previousEntry
QString & append(QChar ch)
int dataSize() const
Return memory usage in bytes.
QSizeF viewboxSize
SVG viewbox size.
void scale(qreal width, qreal height, Qt::AspectRatioMode mode)
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)
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)
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.
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.
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)
QByteArray getImageData(const QString &path) const
Get image data.
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
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
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)
bool operator==(const QgsSvgCacheEntry &other) const
Don't consider image, picture, last used timestamp for comparison.
QgsSvgCacheEntry * nextEntry
QDomNamedNodeMap attributes() const