File indexing completed on 2024-04-14 03:52:05

0001 /*  This file is part of the KDE project.
0002     SPDX-FileCopyrightText: 2010 Michael Pyne <mpyne@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #ifndef KIMAGECACHE_H
0008 #define KIMAGECACHE_H
0009 
0010 // check that KGUIADDONS_LIB is defined in case the application is not using CMake
0011 // (if KGUIADDONS_LIB is not defined, we cannot assume that KCOREADDONS_LIB not being
0012 // defined means that we are not linked against KCoreAddons)
0013 #if defined(KGUIADDONS_LIB) && !defined(KCOREADDONS_LIB)
0014 #ifdef __GNUC__
0015 #warning "KImageCache requires KF6CoreAddons (for kshareddatacache.h)"
0016 #else
0017 #pragma message("KImageCache requires KF6CoreAddons (for kshareddatacache.h)")
0018 #endif
0019 #endif
0020 
0021 #include <klocalimagecacheimpl.h>
0022 #include <kshareddatacache.h>
0023 
0024 #include <QImage>
0025 #include <QPixmap>
0026 
0027 #define KImageCache KSharedPixmapCacheMixin<KSharedDataCache>
0028 
0029 /**
0030  * @brief A simple wrapping layer over KSharedDataCache to support caching
0031  * images and pixmaps.
0032  *
0033  * This class can be used to share images between different processes, which
0034  * is useful when it is known that such images will be used across many
0035  * processes, or when creating the image is expensive.
0036  *
0037  * In addition, the class also supports caching QPixmaps <em>in a single
0038  * process</em> using the setPixmapCaching() function.
0039  *
0040  * Tips for use: If you already have QPixmaps that you intend to use, and
0041  * you do not need access to the actual image data, then try to store and
0042  * retrieve QPixmaps for use.
0043  *
0044  * On the other hand, if you will need to store and retrieve actual image
0045  * data (to modify the image after retrieval for instance) then you should
0046  * use QImage to save the conversion cost from QPixmap to QImage.
0047  *
0048  * KSharedPixmapCacheMixin is a subclass of KSharedDataCache, so all of the methods that
0049  * can be used with KSharedDataCache can be used with KSharedPixmapCacheMixin,
0050  * <em>with the exception of KSharedDataCache::insert() and
0051  * KSharedDataCache::find()</em>.
0052  *
0053  * @author Michael Pyne <mpyne@kde.org>
0054  * @since 4.5
0055  */
0056 template<class T>
0057 class KSharedPixmapCacheMixin : public T, private KLocalImageCacheImplementation
0058 {
0059 public:
0060     /**
0061      * Constructs an image cache, named by @p cacheName, with a default
0062      * size of @p defaultCacheSize.
0063      *
0064      * @param cacheName Name of the cache to use.
0065      * @param defaultCacheSize The default size, in bytes, of the cache.
0066      *  The actual on-disk size will be slightly larger. If the cache already
0067      *  exists, it will not be resized. If it is required to resize the
0068      *  cache then use the deleteCache() function to remove that cache first.
0069      * @param expectedItemSize The expected general size of the items to be
0070      *  added to the image cache, in bytes. Use 0 if you just want a default
0071      *  item size.
0072      */
0073     KSharedPixmapCacheMixin(const QString &cacheName, unsigned defaultCacheSize, unsigned expectedItemSize = 0)
0074         : T(cacheName, defaultCacheSize, expectedItemSize)
0075         , KLocalImageCacheImplementation(defaultCacheSize)
0076     {
0077     }
0078 
0079     /**
0080      * Inserts the pixmap given by @p pixmap to the cache, accessible with
0081      * @p key. The pixmap must be converted to a QImage in order to be stored
0082      * into shared memory. In order to prevent unnecessary conversions from
0083      * taking place @p pixmap will also be cached (but not in shared
0084      * memory) and would be accessible using findPixmap() if pixmap caching is
0085      * enabled.
0086      *
0087      * @param key Name to access @p pixmap with.
0088      * @param pixmap The pixmap to add to the cache.
0089      * @return true if the pixmap was successfully cached, false otherwise.
0090      * @see setPixmapCaching()
0091      */
0092     bool insertPixmap(const QString &key, const QPixmap &pixmap)
0093     {
0094         insertLocalPixmap(key, pixmap);
0095 
0096         // One thing to think about is only inserting things to the shared cache
0097         // that are frequently used. But that would require tracking the use count
0098         // in our local cache too, which I think is probably too much work.
0099 
0100         return insertImage(key, pixmap.toImage());
0101     }
0102 
0103     /**
0104      * Inserts the @p image into the shared cache, accessible with @p key. This
0105      * variant is preferred over insertPixmap() if your source data is already a
0106      * QImage, if it is essential that the image be in shared memory (such as
0107      * for SVG icons which have a high render time), or if it will need to be
0108      * in QImage form after it is retrieved from the cache.
0109      *
0110      * @param key Name to access @p image with.
0111      * @param image The image to add to the shared cache.
0112      * @return true if the image was successfully cached, false otherwise.
0113      */
0114     bool insertImage(const QString &key, const QImage &image)
0115     {
0116         if (this->insert(key, serializeImage(image))) {
0117             updateModifiedTime();
0118             return true;
0119         }
0120 
0121         return false;
0122     }
0123 
0124     /**
0125      * Copies the cached pixmap identified by @p key to @p destination. If no such
0126      * pixmap exists @p destination is unchanged.
0127      *
0128      * @return true if the pixmap identified by @p key existed, false otherwise.
0129      * @see setPixmapCaching()
0130      */
0131     bool findPixmap(const QString &key, QPixmap *destination) const
0132     {
0133         if (findLocalPixmap(key, destination)) {
0134             return true;
0135         }
0136 
0137         QByteArray cachedData;
0138         if (!this->find(key, &cachedData) || cachedData.isNull()) {
0139             return false;
0140         }
0141 
0142         if (destination) {
0143             destination->loadFromData(cachedData, "PNG");
0144 
0145             // Manually re-insert to pixmap cache if we'll be using this one.
0146             insertLocalPixmap(key, *destination);
0147         }
0148 
0149         return true;
0150     }
0151 
0152     /**
0153      * Copies the cached image identified by @p key to @p destination. If no such
0154      * image exists @p destination is unchanged.
0155      *
0156      * @return true if the image identified by @p key existed, false otherwise.
0157      */
0158     bool findImage(const QString &key, QImage *destination) const
0159     {
0160         QByteArray cachedData;
0161         if (!this->find(key, &cachedData) || cachedData.isNull()) {
0162             return false;
0163         }
0164 
0165         if (destination) {
0166             destination->loadFromData(cachedData, "PNG");
0167         }
0168 
0169         return true;
0170     }
0171 
0172     /**
0173      * Removes all entries from the cache. In addition any cached pixmaps (as per
0174      * setPixmapCaching()) are also removed.
0175      */
0176     void clear()
0177     {
0178         clearLocalCache();
0179         T::clear();
0180     }
0181 
0182     /**
0183      * @return The time that an image or pixmap was last inserted into a cache.
0184      */
0185     using KLocalImageCacheImplementation::lastModifiedTime;
0186 
0187     /**
0188      * @return if QPixmaps added with insertPixmap() will be stored in a local
0189      * pixmap cache as well as the shared image cache. The default is to cache
0190      * pixmaps locally.
0191      */
0192     using KLocalImageCacheImplementation::pixmapCaching;
0193 
0194     /**
0195      * Enables or disables local pixmap caching. If it is anticipated that a pixmap
0196      * will be frequently needed then this can actually save memory overall since the
0197      * X server or graphics card will not have to store duplicate copies of the same
0198      * image.
0199      *
0200      * @param enable Enables pixmap caching if true, disables otherwise.
0201      */
0202     using KLocalImageCacheImplementation::setPixmapCaching;
0203 
0204     /**
0205      * @return The highest memory size in bytes to be used by cached pixmaps.
0206      * @since 4.6
0207      */
0208     using KLocalImageCacheImplementation::pixmapCacheLimit;
0209 
0210     /**
0211      * Sets the highest memory size the pixmap cache should use.
0212      *
0213      * @param size The size in bytes
0214      * @since 4.6
0215      */
0216     using KLocalImageCacheImplementation::setPixmapCacheLimit;
0217 };
0218 
0219 #endif /* KIMAGECACHE_H */