28 #include <QApplication> 
   29 #include <QCoreApplication> 
   31 #include <QDomDocument> 
   32 #include <QDomElement> 
   38 #include <QNetworkReply> 
   39 #include <QNetworkRequest> 
   41 #include <QImageReader> 
   42 #include <QSvgRenderer> 
   46 QgsImageCacheEntry::QgsImageCacheEntry( 
const QString &path, QSize size, 
const bool keepAspectRatio, 
const double opacity, 
double dpi )
 
   49   , keepAspectRatio( keepAspectRatio )
 
   57   const QgsImageCacheEntry *otherImage = 
dynamic_cast< const QgsImageCacheEntry * 
>( other );
 
   59   if ( !otherImage || otherImage->keepAspectRatio != keepAspectRatio || otherImage->size != size || ( !size.isValid() && otherImage->targetDpi != targetDpi ) || otherImage->opacity != opacity || otherImage->path != path )
 
   65 int QgsImageCacheEntry::dataSize()
 const 
   68   if ( !image.isNull() )
 
   70     size += image.sizeInBytes();
 
   75 void QgsImageCacheEntry::dump()
 const 
   77   QgsDebugMsgLevel( QStringLiteral( 
"path: %1, size %2x%3" ).arg( path ).arg( size.width() ).arg( size.height() ), 3 );
 
   82 static const int DEFAULT_IMAGE_CACHE_MAX_BYTES = 104857600;
 
   85   : 
QgsAbstractContentCache< QgsImageCacheEntry >( parent, QObject::tr( 
"Image" ),  DEFAULT_IMAGE_CACHE_MAX_BYTES )
 
   87   int bytes = 
QgsSettings().
value( QStringLiteral( 
"/qgis/maxImageCacheSize" ), 0 ).toInt();
 
   93   mMissingSvg = QStringLiteral( 
"<svg width='10' height='10'><text x='5' y='10' font-size='10' text-anchor='middle'>?</text></svg>" ).toLatin1();
 
   96   if ( QFile::exists( downloadingSvgPath ) )
 
   98     QFile file( downloadingSvgPath );
 
   99     if ( file.open( QIODevice::ReadOnly ) )
 
  101       mFetchingSvg = file.readAll();
 
  105   if ( mFetchingSvg.isEmpty() )
 
  107     mFetchingSvg = QStringLiteral( 
"<svg width='10' height='10'><text x='5' y='10' font-size='10' text-anchor='middle'>?</text></svg>" ).toLatin1();
 
  113 QImage 
QgsImageCache::pathAsImage( 
const QString &f, 
const QSize size, 
const bool keepAspectRatio, 
const double opacity, 
bool &fitsInCache, 
bool blocking, 
double targetDpi, 
bool *isMissing )
 
  115   const QString file = f.trimmed();
 
  119   if ( file.isEmpty() )
 
  122   const QMutexLocker locker( &
mMutex );
 
  126   QgsImageCacheEntry *currentEntry = 
findExistingEntry( 
new QgsImageCacheEntry( file, size, keepAspectRatio, opacity, targetDpi ) );
 
  133   if ( currentEntry->image.isNull() )
 
  135     long cachedDataSize = 0;
 
  136     bool isBroken = 
false;
 
  137     result = renderImage( file, size, keepAspectRatio, opacity, targetDpi, isBroken, blocking );
 
  138     cachedDataSize += result.sizeInBytes();
 
  142       currentEntry->image = QImage();
 
  147       currentEntry->image = result;
 
  151       *isMissing = isBroken;
 
  152     currentEntry->isMissingImage = isBroken;
 
  158     result = currentEntry->image;
 
  160       *isMissing = currentEntry->isMissingImage;
 
  168   if ( path.isEmpty() )
 
  172   if ( !path.startsWith( QLatin1String( 
"base64:" ) ) && QFile::exists( path ) )
 
  174     const QImageReader reader( path );
 
  175     if ( reader.size().isValid() )
 
  176       return reader.size();
 
  178       return QImage( path ).size();
 
  182     QByteArray ba = 
getContent( path, QByteArray( 
"broken" ), QByteArray( 
"fetching" ), blocking );
 
  184     if ( ba != 
"broken" && ba != 
"fetching" )
 
  186       QBuffer buffer( &ba );
 
  187       buffer.open( QIODevice::ReadOnly );
 
  189       QImageReader reader( &buffer );
 
  192       const QSize s = reader.size();
 
  195       const QImage im = reader.read();
 
  196       return im.isNull() ? QSize() : im.size();
 
  202 QImage QgsImageCache::renderImage( 
const QString &path, QSize size, 
const bool keepAspectRatio, 
const double opacity, 
double targetDpi, 
bool &isBroken, 
bool blocking )
 const 
  208   if ( !path.startsWith( QLatin1String( 
"base64:" ) ) && QFile::exists( path ) )
 
  210     QImageReader reader( path );
 
  211     reader.setAutoTransform( 
true );
 
  213     if ( reader.format() == 
"pdf" )
 
  215       if ( !size.isEmpty() )
 
  222         reader.setScaledSize( size );
 
  227         const QSize sizeAt72Dpi = reader.size();
 
  228         const QSize sizeAtTargetDpi = sizeAt72Dpi * targetDpi / 72;
 
  229         reader.setScaledSize( sizeAtTargetDpi );
 
  237     QByteArray ba = 
getContent( path, QByteArray( 
"broken" ), QByteArray( 
"fetching" ), blocking );
 
  239     if ( ba == 
"broken" )
 
  244       if ( !size.isValid() )
 
  248       if ( size.width() == 0 )
 
  249         size.setWidth( size.height() );
 
  250       if ( size.height() == 0 )
 
  251         size.setHeight( size.width() );
 
  253       im = QImage( size, QImage::Format_ARGB32_Premultiplied );
 
  257       QSvgRenderer r( mMissingSvg );
 
  259       QSizeF s( r.viewBox().size() );
 
  260       s.scale( size.width(), size.height(), Qt::KeepAspectRatio );
 
  261       const QRectF rect( ( size.width() - s.width() ) / 2, ( size.height() - s.height() ) / 2, s.width(), s.height() );
 
  262       r.render( &p, rect );
 
  264     else if ( ba == 
"fetching" )
 
  267       if ( size.width() == 0 )
 
  268         size.setWidth( size.height() );
 
  269       if ( size.height() == 0 )
 
  270         size.setHeight( size.width() );
 
  273       im = QImage( size, QImage::Format_ARGB32_Premultiplied );
 
  277       QSvgRenderer r( mFetchingSvg );
 
  279       QSizeF s( r.viewBox().size() );
 
  280       s.scale( size.width(), size.height(), Qt::KeepAspectRatio );
 
  281       const QRectF rect( ( size.width() - s.width() ) / 2, ( size.height() - s.height() ) / 2, s.width(), s.height() );
 
  282       r.render( &p, rect );
 
  286       QBuffer buffer( &ba );
 
  287       buffer.open( QIODevice::ReadOnly );
 
  289       QImageReader reader( &buffer );
 
  290       reader.setAutoTransform( 
true );
 
  292       if ( reader.format() == 
"pdf" )
 
  294         if ( !size.isEmpty() )
 
  301           reader.setScaledSize( size );
 
  306           const QSize sizeAt72Dpi = reader.size();
 
  307           const QSize sizeAtTargetDpi = sizeAt72Dpi * targetDpi / 72;
 
  308           reader.setScaledSize( sizeAtTargetDpi );
 
  316   if ( !im.hasAlphaChannel() )
 
  317     im = im.convertToFormat( QImage::Format_ARGB32 );
 
  323   if ( !size.isValid() || size.isNull() || im.size() == size )
 
  326   else if ( keepAspectRatio && size.height() == 0 )
 
  327     return im.scaledToWidth( size.width(), Qt::SmoothTransformation );
 
  329   else if ( keepAspectRatio && size.width() == 0 )
 
  330     return im.scaledToHeight( size.height(), Qt::SmoothTransformation );
 
  332     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.
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, bool blocking=false, double targetDpi=96, bool *isMissing=nullptr)
Returns the specified path rendered as an image.
static void multiplyOpacity(QImage &image, double factor, QgsFeedback *feedback=nullptr)
Multiplies opacity of image pixel values by a factor.
This class is a composition of two QSettings instances:
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
#define QgsDebugMsgLevel(str, level)