[Digikam-devel] extragear/graphics/digikam

Marcel Wiesweg marcel.wiesweg at gmx.de
Wed Jan 3 16:45:44 GMT 2007


SVN commit 619531 by mwiesweg:

Loading of previews is now multithreaded:
- integrate preview loading into the load-save framework
- the PreviewLoadTask is a cut-down version of the normal SharedLoadingTask
- use the same cache

CCMAIL: digikam-devel at kde.org



 M  +0 -1      digikam/Makefile.am  
 M  +31 -43    digikam/imagepreviewwidget.cpp  
 M  +4 -4      digikam/imagepreviewwidget.h  
 M  +4 -0      libs/threadimageio/Makefile.am  
 M  +11 -3     libs/threadimageio/loadingcache.cpp  
 M  +24 -0     libs/threadimageio/loadingdescription.h  
 M  +1 -1      libs/threadimageio/loadsavetask.cpp  
 M  +1 -1      libs/threadimageio/loadsavetask.h  
 M  +13 -3     libs/threadimageio/loadsavethread.cpp  
 M  +40 -0     libs/threadimageio/managedloadsavethread.cpp  
 M  +1 -0      libs/threadimageio/managedloadsavethread.h  
 A             libs/threadimageio/previewloadthread.cpp   [License: GPL]
 A             libs/threadimageio/previewloadthread.h   [License: GPL]
 A             libs/threadimageio/previewtask.cpp   [License: GPL]
 A             libs/threadimageio/previewtask.h   [License: GPL]


--- trunk/extragear/graphics/digikam/digikam/Makefile.am #619530:619531
@@ -67,7 +67,6 @@
 	                    iconitem.cpp \
 	                    imageattributeswatch.cpp \
 	                    imageinfo.cpp \
-	                    imagepreviewjob.cpp \
 	                    imagepreviewwidget.cpp \
 	                    imagepreviewview.cpp \
 	                    kdatetimeedit.cpp \
--- trunk/extragear/graphics/digikam/digikam/imagepreviewwidget.cpp #619530:619531
@@ -37,9 +37,9 @@
 // Local includes.
 
 #include "ddebug.h"
+#include "previewloadthread.h"
 #include "themeengine.h"
 #include "albumsettings.h"
-#include "imagepreviewjob.h"
 #include "imagepreviewwidget.h"
 #include "imagepreviewwidget.moc"
 
@@ -52,7 +52,7 @@
 
     ImagePreviewWidgetPriv()
     {
-        previewJob        = 0;
+        previewThread      = 0;
     }
 
     QString                       path;
@@ -60,8 +60,8 @@
     QPixmap                       pixmap;
 
     QImage                        preview;
-    
-    QGuardedPtr<ImagePreviewJob>  previewJob;
+
+    PreviewLoadThread            *previewThread;
 };
 
 ImagePreviewWidget::ImagePreviewWidget(QWidget *parent)
@@ -83,11 +83,7 @@
 
 ImagePreviewWidget::~ImagePreviewWidget()
 {
-    if (!d->previewJob.isNull())
-    {
-        d->previewJob->kill();
-        d->previewJob = 0;
-    }
+    delete d->previewThread;
 
     delete d;
 }
@@ -100,53 +96,43 @@
     d->path = path;
 
     if (d->path.isEmpty())
-	slotFailedImagePreview(KURL());
+    {
+        d->pixmap  = QPixmap(contentsRect().size());
 
-    if (!d->previewJob.isNull())
+        updatePixmap();
+        update();
+        unsetCursor();
+        emit previewFailed();
+    }
+
+    if (!d->previewThread)
     {
-        d->previewJob->kill();
-        d->previewJob = 0;
+        d->previewThread = new PreviewLoadThread();
+        connect(d->previewThread, SIGNAL(signalPreviewLoaded(const LoadingDescription &, const QImage &)),
+                this, SLOT(slotGotImagePreview(const LoadingDescription &, const QImage&)));
     }
 
-    d->previewJob = new ImagePreviewJob(KURL(path), 1024, AlbumSettings::instance()->getExifRotate());
+    d->previewThread->load(LoadingDescription(path, 1024, AlbumSettings::instance()->getExifRotate()));
 
-    connect(d->previewJob, SIGNAL(signalImagePreview(const KURL&, const QImage&)),
-            this, SLOT(slotGotImagePreview(const KURL&, const QImage&)));
-
-    connect(d->previewJob, SIGNAL(signalFailed(const KURL&)),
-            this, SLOT(slotFailedImagePreview(const KURL&)));   
-
     emit previewStarted();
 }
 
-void ImagePreviewWidget::slotGotImagePreview(const KURL&, const QImage& preview)
+void ImagePreviewWidget::slotGotImagePreview(const LoadingDescription &description, const QImage& preview)
 {
+    if (description.filePath != d->path)
+        return;
+
     d->preview = preview;
     d->pixmap  = QPixmap(contentsRect().size());
 
-    // It is very important to kill the thumbnail job properly
-    // so that is frees its shared memory. Otherwise the memory
-    // will _never_ be freed, see b.k.o. #131277
-    if (!d->previewJob.isNull())
-    {
-        d->previewJob->kill();
-        d->previewJob = 0;
-    }
-
     updatePixmap();
-    repaint(false);
+    update();
     unsetCursor();
-    emit previewComplete();
-}
 
-void ImagePreviewWidget::slotFailedImagePreview(const KURL&)
-{
-    d->preview = QImage();
-    d->pixmap  = QPixmap(contentsRect().size());
-    updatePixmap();
-    repaint(false);
-    unsetCursor();
-    emit previewFailed();
+    if (preview.isNull())
+        emit previewFailed();
+    else
+        emit previewComplete();
 }
 
 void ImagePreviewWidget::updatePixmap( void )
@@ -178,12 +164,14 @@
     }
     else
     {
-        // There is nothing to see.
-        
+        // There is nothing to see: Empty album, or initially waiting to load preview
+
+        /*
         p.setPen(QPen(ThemeEngine::instance()->textRegColor()));
         p.drawText(0, 0, d->pixmap.width(), d->pixmap.height(),
                     Qt::AlignCenter|Qt::WordBreak, 
                     i18n("No item to preview in this album."));
+        */
     }
     
     p.end();
--- trunk/extragear/graphics/digikam/digikam/imagepreviewwidget.h #619530:619531
@@ -29,6 +29,7 @@
 // Local includes
 
 #include "digikam_export.h"
+#include "loadingdescription.h"
 
 class QPixmap;
 
@@ -70,10 +71,9 @@
     void wheelEvent(QWheelEvent * e);
 
 private slots:
-    
-    void slotGotImagePreview(const KURL&, const QImage& preview);
-    void slotFailedImagePreview(const KURL&);
-    
+
+    void slotGotImagePreview(const LoadingDescription &loadingDescription, const QImage &image);
+
 private:
 
     void updatePixmap(void);
--- trunk/extragear/graphics/digikam/libs/threadimageio/Makefile.am #619530:619531
@@ -5,7 +5,9 @@
 libthreadimageio_la_SOURCES = loadsavethread.cpp \
                               managedloadsavethread.cpp \
                               sharedloadsavethread.cpp \
+                              previewloadthread.cpp \
                               loadsavetask.cpp \
+                              previewtask.cpp \
                               loadingcache.cpp \
                               loadingcacheinterface.cpp
 
@@ -13,5 +15,7 @@
 
 INCLUDES = -I$(top_srcdir)/digikam/libs/dimg \
 	       -I$(top_srcdir)/digikam/libs/dimg/loaders \
+	       -I$(top_srcdir)/digikam/libs/dmetadata \
+	       -I$(top_srcdir)/digikam/libs/dcraw \
 	       -I$(top_srcdir)/digikam/digikam \
 	       $(all_includes)
--- trunk/extragear/graphics/digikam/libs/threadimageio/loadingcache.cpp #619530:619531
@@ -88,9 +88,17 @@
 bool LoadingCache::putImage(const QString &cacheKey, DImg *img, const QString &filePath)
 {
     bool successfullyInserted;
-    // use size of image as cache cost
-    if ( d->imageCache.insert(cacheKey, img, img->numBytes()) )
+
+    // use size of image as cache cost, take care for wrapped preview QImages
+    int cost = img->numBytes();
+    QVariant attribute(img->attribute("previewQImage"));
+    if (attribute.isValid())
     {
+        cost = attribute.toImage().numBytes();
+    }
+
+    if ( d->imageCache.insert(cacheKey, img, cost) )
+    {
         if (!filePath.isEmpty())
         {
             // store file path as attribute for our own use
@@ -141,7 +149,7 @@
     }
 }
 
-void LoadingCache::customEvent(QCustomEvent *event)
+void LoadingCache::customEvent(QCustomEvent *)
 {
     // Event comes from main thread, we need to lock ourselves.
     CacheLock lock(this);
--- trunk/extragear/graphics/digikam/libs/threadimageio/loadingdescription.h #619530:619531
@@ -34,6 +34,18 @@
 {
 public:
 
+    class PreviewParameters
+    {
+    public:
+        PreviewParameters()
+        {
+            size = 0;
+            exifRotate = false;
+        }
+        int size;
+        bool exifRotate;
+    };
+
     /*
         An invalid LoadingDescription
     */
@@ -59,8 +71,20 @@
         : filePath(filePath), rawDecodingSettings(settings)
         {};
 
+    /*
+        For preview jobs:
+        Stores preview max size and exif rotation
+    */
+    LoadingDescription(const QString &filePath, int size, bool exifRotate)
+        : filePath(filePath)
+        {
+            previewParameters.size       = size;
+            previewParameters.exifRotate = exifRotate;
+        };
+
     QString             filePath;
     RawDecodingSettings rawDecodingSettings;
+    PreviewParameters   previewParameters;
 
     /*
         Return the cache key this description shall be stored as
--- trunk/extragear/graphics/digikam/libs/threadimageio/loadsavetask.cpp #619530:619531
@@ -284,7 +284,7 @@
         // set to 0, as checked in setStatus
         m_usedProcess = 0;
     }
-};
+}
 
 void SharedLoadingTask::progressInfo(const DImg *, float progress)
 {
--- trunk/extragear/graphics/digikam/libs/threadimageio/loadsavetask.h #619530:619531
@@ -284,7 +284,7 @@
     virtual QObject *eventReceiver();
     virtual LoadSaveThread::AccessMode accessMode();
 
-private:
+protected:
 
     LoadSaveThread::AccessMode m_accessMode;
     bool m_completed;
--- trunk/extragear/graphics/digikam/libs/threadimageio/loadsavethread.cpp #619530:619531
@@ -38,6 +38,8 @@
     // so we do not need to store check for every option here.
     if (rawDecodingSettings.halfSizeColorImage)
         return filePath + "-halfSizeColorImage";
+    else if (previewParameters.size)
+        return filePath + "-previewImage";
     else
         return filePath;
 }
@@ -51,13 +53,16 @@
     keys.append(filePath);
     if (rawDecodingSettings.halfSizeColorImage)
         keys.append(filePath + "-halfSizeColorImage");
+    if (previewParameters.size)
+        keys.append(filePath + "-previewImage");
     return keys;
 }
 
 bool LoadingDescription::isReducedVersion() const
 {
-    // currently the only way to get a reduced, speed optimized loading
-    return rawDecodingSettings.halfSizeColorImage;
+    // return true if this loads anything but the full version
+    return rawDecodingSettings.halfSizeColorImage
+        || previewParameters.size;
 }
 
 bool LoadingDescription::operator==(const LoadingDescription &other) const
@@ -65,7 +70,8 @@
     // NOTE: If we start loading RAW files with different loading settings in parallel,
     //       this and the next methods must be better implemented!
     return filePath == other.filePath &&
-            rawDecodingSettings.halfSizeColorImage == other.rawDecodingSettings.halfSizeColorImage;
+            rawDecodingSettings.halfSizeColorImage == other.rawDecodingSettings.halfSizeColorImage &&
+            previewParameters.size == other.previewParameters.size;
 }
 
 bool LoadingDescription::equalsIgnoreReducedVersion(const LoadingDescription &other) const
@@ -79,6 +85,10 @@
             (
              (rawDecodingSettings.halfSizeColorImage == other.rawDecodingSettings.halfSizeColorImage) ||
              other.rawDecodingSettings.halfSizeColorImage
+            ) &&
+            (
+             (previewParameters.size == other.previewParameters.size) ||
+              other.previewParameters.size
             );
 }
 
--- trunk/extragear/graphics/digikam/libs/threadimageio/managedloadsavethread.cpp #619530:619531
@@ -24,6 +24,7 @@
 #include "ddebug.h"
 #include "managedloadsavethread.h"
 #include "loadsavetask.h"
+#include "previewtask.h"
 
 namespace Digikam
 {
@@ -205,6 +206,45 @@
     m_condVar.wakeAll();
 }
 
+void ManagedLoadSaveThread::loadPreview(LoadingDescription description)
+{
+    // This is similar to the LoadingPolicyFirstRemovePrevious policy with normal loading tasks.
+    // Preview threads typically only support preview tasks,
+    // so no need to differentiate with normal loading tasks.
+
+    QMutexLocker lock(&m_mutex);
+    LoadingTask *loadingTask = 0;
+    LoadingTask *existingTask = findExistingTask(description);
+
+    // reuse task if it exists
+    if (existingTask)
+    {
+        existingTask->setStatus(LoadingTask::LoadingTaskStatusLoading);
+    }
+    // stop current task
+    if (m_currentTask && m_currentTask != existingTask)
+    {
+        if ( (loadingTask = checkLoadingTask(m_currentTask, LoadingTaskFilterAll)) )
+            loadingTask->setStatus(LoadingTask::LoadingTaskStatusStopping);
+    }
+    // remove all loading tasks
+    for (LoadSaveTask *task = m_todo.first(); task; task = m_todo.next())
+    {
+        if (task != existingTask && checkLoadingTask(task, LoadingTaskFilterAll))
+        {
+            m_todo.remove();
+            m_todo.prev();
+        }
+    }
+    //DDebug()<<"loadPreview for " << description.filePath << " existingTask " << existingTask << " currentTask " << m_currentTask << endl;
+    // append new loading task
+    if (existingTask)
+        return;
+    m_todo.append(new PreviewLoadingTask(this, description));
+    m_condVar.wakeAll();
+}
+
+
 LoadingTask *ManagedLoadSaveThread::createLoadingTask(const LoadingDescription &description,
          bool preloading, LoadingMode loadingMode, AccessMode accessMode)
 {
--- trunk/extragear/graphics/digikam/libs/threadimageio/managedloadsavethread.h #619530:619531
@@ -108,6 +108,7 @@
 
     void load(LoadingDescription description, LoadingMode loadingMode,
               LoadingPolicy policy = LoadingPolicyAppend, AccessMode mode = AccessModeReadWrite);
+    void loadPreview(LoadingDescription description);
 
 private:
 



More information about the Digikam-devel mailing list