[ui] ImageGallery: faster thumbnail dispatch using caller ID

This commit is contained in:
mugulmd 2023-01-16 06:21:48 -08:00
parent 8551135514
commit 80174e22af
3 changed files with 19 additions and 15 deletions

View file

@ -49,8 +49,10 @@ class ThumbnailCache(QObject):
maxThumbnailsOnDisk = 100000 maxThumbnailsOnDisk = 100000
# Signal to notify listeners that a thumbnail was created and written on disk # Signal to notify listeners that a thumbnail was created and written on disk
# This signal has one argument: the url of the image that the thumbnail is associated to # This signal has two argument:
thumbnailCreated = Signal(QUrl) # - the url of the image that the thumbnail is associated to
# - an identifier for the caller, e.g. the component that sent the request (useful for faster dispatch in QML)
thumbnailCreated = Signal(QUrl, int)
# Thread pool for running createThumbnail asynchronously on a fixed number of worker threads # Thread pool for running createThumbnail asynchronously on a fixed number of worker threads
pool = ThreadPool(processes=3) pool = ThreadPool(processes=3)
@ -93,15 +95,16 @@ class ThumbnailCache(QObject):
path = os.path.join(ThumbnailCache.thumbnailDir, f'{digest}.jpg') path = os.path.join(ThumbnailCache.thumbnailDir, f'{digest}.jpg')
return path return path
@Slot(QUrl, result=QUrl) @Slot(QUrl, int, result=QUrl)
def thumbnail(self, imgSource): def thumbnail(self, imgSource, callerID):
"""Retrieve the filepath of the thumbnail corresponding to a given image. """Retrieve the filepath of the thumbnail corresponding to a given image.
If the thumbnail does not exist on disk, it will be created asynchronously. If the thumbnail does not exist on disk, it will be created asynchronously.
When this is done, the createdThumbnail signal is emitted. When this is done, the thumbnailCreated signal is emitted.
Args: Args:
imgSource (QUrl): location of the input image imgSource (QUrl): location of the input image
callerID (int): identifier for the object that requested the thumbnail
Returns: Returns:
QUrl: location of the corresponding thumbnail if it exists, otherwise None QUrl: location of the corresponding thumbnail if it exists, otherwise None
@ -121,14 +124,15 @@ class ThumbnailCache(QObject):
# Thumbnail does not exist # Thumbnail does not exist
# create it in a worker thread to avoid UI freeze # create it in a worker thread to avoid UI freeze
ThumbnailCache.pool.apply_async(self.createThumbnail, args=(imgSource,)) ThumbnailCache.pool.apply_async(self.createThumbnail, args=(imgSource,callerID,))
return None return None
def createThumbnail(self, imgSource): def createThumbnail(self, imgSource, callerID):
"""Load an image, resize it to thumbnail dimensions and save the result in the cache directory. """Load an image, resize it to thumbnail dimensions and save the result in the cache directory.
Args: Args:
imgSource (QUrl): location of the input image imgSource (QUrl): location of the input image
callerID (int): identifier for the object that requested the thumbnail
""" """
imgPath = imgSource.toLocalFile() imgPath = imgSource.toLocalFile()
path = ThumbnailCache.thumbnailPath(imgPath) path = ThumbnailCache.thumbnailPath(imgPath)
@ -155,7 +159,7 @@ class ThumbnailCache(QObject):
logging.error(f'[ThumbnailCache] Error when writing thumbnail: {writer.errorString()}') logging.error(f'[ThumbnailCache] Error when writing thumbnail: {writer.errorString()}')
# Notify listeners # Notify listeners
self.thumbnailCreated.emit(imgSource) self.thumbnailCreated.emit(imgSource, callerID)
@staticmethod @staticmethod
def clean(): def clean():

View file

@ -11,6 +11,7 @@ Item {
id: root id: root
property variant viewpoint property variant viewpoint
property int cellID
property bool isCurrentItem: false property bool isCurrentItem: false
property alias source: _viewpoint.source property alias source: _viewpoint.source
property alias metadata: _viewpoint.metadata property alias metadata: _viewpoint.metadata
@ -34,7 +35,7 @@ Item {
// update thumbnail location // update thumbnail location
// can be called from the GridView when a new thumbnail has been written on disk // can be called from the GridView when a new thumbnail has been written on disk
function updateThumbnail() { function updateThumbnail() {
thumbnail.source = ThumbnailCache.thumbnail(root.source); thumbnail.source = ThumbnailCache.thumbnail(root.source, cellID);
} }
onSourceChanged: { onSourceChanged: {
updateThumbnail(); updateThumbnail();

View file

@ -203,15 +203,13 @@ Panel {
// Update grid item when corresponding thumbnail is computed // Update grid item when corresponding thumbnail is computed
Connections { Connections {
target: ThumbnailCache target: ThumbnailCache
function onThumbnailCreated(imgSource) { function onThumbnailCreated(imgSource, callerID) {
for (let i = 0; i < grid.count; i++) { let item = grid.itemAtIndex(callerID); // item is an ImageDelegate
let item = grid.itemAtIndex(i); // item is an ImageDelegate
if (item && item.source == imgSource) { if (item && item.source == imgSource) {
item.updateThumbnail(); item.updateThumbnail();
} }
} }
} }
}
model: SortFilterDelegateModel { model: SortFilterDelegateModel {
id: sortedModel id: sortedModel
@ -257,6 +255,7 @@ Panel {
id: imageDelegate id: imageDelegate
viewpoint: object.value viewpoint: object.value
cellID: DelegateModel.filteredIndex
width: grid.cellWidth width: grid.cellWidth
height: grid.cellHeight height: grid.cellHeight
readOnly: m.readOnly readOnly: m.readOnly