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)