27 #include <QApplication> 28 #include <QCoreApplication> 30 #include <QDomDocument> 31 #include <QDomElement> 37 #include <QNetworkReply> 38 #include <QNetworkRequest> 40 #include <QImageReader> 41 #include <QSvgRenderer> 45 QgsImageCacheEntry::QgsImageCacheEntry(
const QString &path, QSize size,
const bool keepAspectRatio,
const double opacity )
48 , keepAspectRatio( keepAspectRatio )
55 const QgsImageCacheEntry *otherImage =
dynamic_cast< const QgsImageCacheEntry *
>( other );
57 if ( !otherImage || otherImage->keepAspectRatio != keepAspectRatio || otherImage->size != size || otherImage->path != path || otherImage->opacity != opacity )
63 int QgsImageCacheEntry::dataSize()
const 66 if ( !image.isNull() )
68 size += ( image.width() * image.height() * 32 );
73 void QgsImageCacheEntry::dump()
const 75 QgsDebugMsg( QStringLiteral(
"path: %1, size %2x%3" ).arg( path ).arg( size.width() ).arg( size.height() ) );
84 mMissingSvg = QStringLiteral(
"<svg width='10' height='10'><text x='5' y='10' font-size='10' text-anchor='middle'>?</text></svg>" ).toLatin1();
87 if ( QFile::exists( downloadingSvgPath ) )
89 QFile file( downloadingSvgPath );
90 if ( file.open( QIODevice::ReadOnly ) )
92 mFetchingSvg = file.readAll();
96 if ( mFetchingSvg.isEmpty() )
98 mFetchingSvg = QStringLiteral(
"<svg width='10' height='10'><text x='5' y='10' font-size='10' text-anchor='middle'>?</text></svg>" ).toLatin1();
106 const QString file = f.trimmed();
108 if ( file.isEmpty() )
111 QMutexLocker locker( &
mMutex );
115 QgsImageCacheEntry *currentEntry =
findExistingEntry(
new QgsImageCacheEntry( file, size, keepAspectRatio, opacity ) );
122 if ( currentEntry->image.isNull() )
124 long cachedDataSize = 0;
125 result = renderImage( file, size, keepAspectRatio, opacity );
126 cachedDataSize += result.width() * result.height() * 32;
130 currentEntry->image = QImage();
134 mTotalSize += ( result.width() * result.height() * 32 );
135 currentEntry->image = result;
141 result = currentEntry->image;
149 if ( path.isEmpty() )
153 if ( QFile::exists( path ) )
155 QImageReader reader( path );
156 if ( reader.size().isValid() )
157 return reader.size();
159 return QImage( path ).size();
163 QByteArray ba =
getContent( path, QByteArray(
"broken" ), QByteArray(
"fetching" ) );
165 if ( ba !=
"broken" && ba !=
"fetching" )
167 QBuffer buffer( &ba );
168 buffer.open( QIODevice::ReadOnly );
170 QImageReader reader( &buffer );
173 const QSize s = reader.size();
176 QImage im = reader.read();
177 return im.isNull() ? QSize() : im.size();
183 QImage QgsImageCache::renderImage(
const QString &path, QSize size,
const bool keepAspectRatio,
const double opacity )
const 187 if ( QFile::exists( path ) )
193 QByteArray ba =
getContent( path, QByteArray(
"broken" ), QByteArray(
"fetching" ) );
195 if ( ba ==
"broken" )
198 if ( size.width() == 0 )
199 size.setWidth( size.height() );
200 if ( size.height() == 0 )
201 size.setHeight( size.width() );
203 im = QImage( size, QImage::Format_ARGB32_Premultiplied );
207 QSvgRenderer r( mMissingSvg );
209 QSizeF s( r.viewBox().size() );
210 s.scale( size.width(), size.height(), Qt::KeepAspectRatio );
211 QRectF rect( ( size.width() - s.width() ) / 2, ( size.height() - s.height() ) / 2, s.width(), s.height() );
212 r.render( &p, rect );
214 else if ( ba ==
"fetching" )
217 if ( size.width() == 0 )
218 size.setWidth( size.height() );
219 if ( size.height() == 0 )
220 size.setHeight( size.width() );
223 im = QImage( size, QImage::Format_ARGB32_Premultiplied );
227 QSvgRenderer r( mFetchingSvg );
229 QSizeF s( r.viewBox().size() );
230 s.scale( size.width(), size.height(), Qt::KeepAspectRatio );
231 QRectF rect( ( size.width() - s.width() ) / 2, ( size.height() - s.height() ) / 2, s.width(), s.height() );
232 r.render( &p, rect );
236 QBuffer buffer( &ba );
237 buffer.open( QIODevice::ReadOnly );
239 QImageReader reader( &buffer );
244 if ( !im.hasAlphaChannel() )
245 im = im.convertToFormat( QImage::Format_ARGB32 );
251 if ( !size.isValid() || size.isNull() || im.size() == size )
254 else if ( keepAspectRatio && size.height() == 0 )
255 return im.scaledToWidth( size.width(), Qt::SmoothTransformation );
257 else if ( keepAspectRatio && size.width() == 0 )
258 return im.scaledToHeight( size.height(), Qt::SmoothTransformation );
260 return im.scaled( size, keepAspectRatio ? Qt::KeepAspectRatio : Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
static void multiplyOpacity(QImage &image, double factor)
Multiplies opacity of image pixel values by a factor.
Abstract base class for file content caches, such as SVG or raster image caches.
QgsImageCache(QObject *parent=nullptr)
Constructor for QgsImageCache, with the specified parent object.
static QString defaultThemePath()
Returns the path to the default theme directory.
Base class for entries in a QgsAbstractContentCache.
void remoteContentFetched(const QString &url)
Emitted when the cache has finished retrieving content from a remote url.
QSize originalSize(const QString &path) const
Returns the original size (in pixels) of the image at the specified path.
void remoteImageFetched(const QString &url)
Emitted when the cache has finished retrieving an image file from a remote url.
QImage pathAsImage(const QString &path, const QSize size, const bool keepAspectRatio, const double opacity, bool &fitsInCache)
Returns the specified path rendered as an image.
QgsImageCacheEntry * findExistingEntry(QgsImageCacheEntry *entryTemplate)
Returns the existing entry from the cache which matches entryTemplate (deleting entryTemplate when do...
long mMaxCacheSize
Maximum cache size.
QByteArray getContent(const QString &path, const QByteArray &missingContent, const QByteArray &fetchingContent) const
Gets the file content corresponding to the given path.
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...