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 QgsDebugMsgLevel( QStringLiteral(
"path: %1, size %2x%3" ).arg( path ).arg( size.width() ).arg( size.height() ), 3 );
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();
104 QImage
QgsImageCache::pathAsImage(
const QString &f,
const QSize size,
const bool keepAspectRatio,
const double opacity,
bool &fitsInCache,
bool blocking,
bool *isMissing )
106 const QString file = f.trimmed();
110 if ( file.isEmpty() )
113 QMutexLocker locker( &
mMutex );
117 QgsImageCacheEntry *currentEntry =
findExistingEntry(
new QgsImageCacheEntry( file, size, keepAspectRatio, opacity ) );
124 if ( currentEntry->image.isNull() )
126 long cachedDataSize = 0;
127 bool isBroken =
false;
128 result = renderImage( file, size, keepAspectRatio, opacity, isBroken, blocking );
129 cachedDataSize += result.width() * result.height() * 32;
133 currentEntry->image = QImage();
137 mTotalSize += ( result.width() * result.height() * 32 );
138 currentEntry->image = result;
142 *isMissing = isBroken;
143 currentEntry->isMissingImage = isBroken;
149 result = currentEntry->image;
151 *isMissing = currentEntry->isMissingImage;
159 if ( path.isEmpty() )
163 if ( !path.startsWith( QLatin1String(
"base64:" ) ) && QFile::exists( path ) )
165 QImageReader reader( path );
166 if ( reader.size().isValid() )
167 return reader.size();
169 return QImage( path ).size();
173 QByteArray ba =
getContent( path, QByteArray(
"broken" ), QByteArray(
"fetching" ), blocking );
175 if ( ba !=
"broken" && ba !=
"fetching" )
177 QBuffer buffer( &ba );
178 buffer.open( QIODevice::ReadOnly );
180 QImageReader reader( &buffer );
183 const QSize s = reader.size();
186 QImage im = reader.read();
187 return im.isNull() ? QSize() : im.size();
193 QImage QgsImageCache::renderImage(
const QString &path, QSize size,
const bool keepAspectRatio,
const double opacity,
bool &isBroken,
bool blocking )
const
199 if ( !path.startsWith( QLatin1String(
"base64:" ) ) && QFile::exists( path ) )
205 QByteArray ba =
getContent( path, QByteArray(
"broken" ), QByteArray(
"fetching" ), blocking );
207 if ( ba ==
"broken" )
212 if ( !size.isValid() )
216 if ( size.width() == 0 )
217 size.setWidth( size.height() );
218 if ( size.height() == 0 )
219 size.setHeight( size.width() );
221 im = QImage( size, QImage::Format_ARGB32_Premultiplied );
225 QSvgRenderer r( mMissingSvg );
227 QSizeF s( r.viewBox().size() );
228 s.scale( size.width(), size.height(), Qt::KeepAspectRatio );
229 QRectF rect( ( size.width() - s.width() ) / 2, ( size.height() - s.height() ) / 2, s.width(), s.height() );
230 r.render( &p, rect );
232 else if ( ba ==
"fetching" )
235 if ( size.width() == 0 )
236 size.setWidth( size.height() );
237 if ( size.height() == 0 )
238 size.setHeight( size.width() );
241 im = QImage( size, QImage::Format_ARGB32_Premultiplied );
245 QSvgRenderer r( mFetchingSvg );
247 QSizeF s( r.viewBox().size() );
248 s.scale( size.width(), size.height(), Qt::KeepAspectRatio );
249 QRectF rect( ( size.width() - s.width() ) / 2, ( size.height() - s.height() ) / 2, s.width(), s.height() );
250 r.render( &p, rect );
254 QBuffer buffer( &ba );
255 buffer.open( QIODevice::ReadOnly );
257 QImageReader reader( &buffer );
262 if ( !im.hasAlphaChannel() )
263 im = im.convertToFormat( QImage::Format_ARGB32 );
269 if ( !size.isValid() || size.isNull() || im.size() == size )
272 else if ( keepAspectRatio && size.height() == 0 )
273 return im.scaledToWidth( size.width(), Qt::SmoothTransformation );
275 else if ( keepAspectRatio && size.width() == 0 )
276 return im.scaledToHeight( size.height(), Qt::SmoothTransformation );
278 return im.scaled( size, keepAspectRatio ? Qt::KeepAspectRatio : Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
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.
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, bool blocking=false) 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.
static QString defaultThemePath()
Returns the path to the default theme directory.
QSize originalSize(const QString &path, bool blocking=false) const
Returns the original size (in pixels) of the image at the specified path.
QgsImageCache(QObject *parent=nullptr)
Constructor for QgsImageCache, with the specified parent object.
QImage pathAsImage(const QString &path, const QSize size, const bool keepAspectRatio, const double opacity, bool &fitsInCache, bool blocking=false, bool *isMissing=nullptr)
Returns the specified path rendered as an image.
void remoteImageFetched(const QString &url)
Emitted when the cache has finished retrieving an image file from a remote url.
static void multiplyOpacity(QImage &image, double factor)
Multiplies opacity of image pixel values by a factor.
#define QgsDebugMsgLevel(str, level)