reworked image manager _cache to contain unique images (to be cleaned up)

This commit is contained in:
Andreas Preikschat 2012-06-30 17:19:33 +02:00
parent 78753d03dc
commit 9da23266c6
9 changed files with 77 additions and 72 deletions

View File

@ -96,6 +96,15 @@ class Priority(object):
Urgent = 0 Urgent = 0
class ImageSource(object):
"""
This enumeration class represents different image sources. An image sources
states where an image is used.
"""
ImagePlugin = 1
Theme = 2
class Image(object): class Image(object):
""" """
This class represents an image. To mark an image as *dirty* call the This class represents an image. To mark an image as *dirty* call the
@ -103,27 +112,22 @@ class Image(object):
argument. argument.
""" """
secondary_priority = 0 secondary_priority = 0
def __init__(self, name, path, source, background): def __init__(self, path, source, background):
""" """
Create an image for the :class:`ImageManager`'s cache. Create an image for the :class:`ImageManager`'s cache.
``name``
The image name. This does not have to be part of the ``path``. It
can be of any value. It can be considered an ID.
``path`` ``path``
The image's file path. This should be an existing file path. The image's file path. This should be an existing file path.
``source`` ``source``
The source describes the image's origin. Possible values are The source describes the image's origin. Possible values are
``image`` and ``theme``. ``image`` and ``theme``.
``background`` ``background``
A ``QtGui.QColor`` object specifying the colour to be used to fill A ``QtGui.QColor`` object specifying the colour to be used to fill
the gabs if the image's ratio does not match with the display ratio. the gabs if the image's ratio does not match with the display ratio.
""" """
self.name = name
self.path = path self.path = path
self.image = None self.image = None
self.image_bytes = None self.image_bytes = None
@ -192,6 +196,7 @@ class ImageManager(QtCore.QObject):
self.imageThread = ImageThread(self) self.imageThread = ImageThread(self)
self._conversionQueue = PriorityQueue() self._conversionQueue = PriorityQueue()
self.stopManager = False self.stopManager = False
self.imageSource = ImageSource()
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_updated'), self.processUpdates) QtCore.SIGNAL(u'config_updated'), self.processUpdates)
@ -220,14 +225,14 @@ class ImageManager(QtCore.QObject):
image.background = background image.background = background
self._resetImage(image) self._resetImage(image)
def updateImageBorder(self, name, source, background): def updateImageBorder(self, path, source, background):
""" """
Border has changed so update the image affected. Border has changed so update the image affected.
""" """
log.debug(u'updateImage') log.debug(u'updateImage')
# Mark the image as dirty for a rebuild by setting the image and byte # Mark the image as dirty for a rebuild by setting the image and byte
# stream to None. # stream to None.
image = self._cache[name] image = self._cache[(path, source)]
if image.source == source: if image.source == source:
image.background = background image.background = background
self._resetImage(image) self._resetImage(image)
@ -249,13 +254,13 @@ class ImageManager(QtCore.QObject):
if not self.imageThread.isRunning(): if not self.imageThread.isRunning():
self.imageThread.start() self.imageThread.start()
def getImage(self, name): def getImage(self, path, source):
""" """
Return the ``QImage`` from the cache. If not present wait for the Return the ``QImage`` from the cache. If not present wait for the
background thread to process it. background thread to process it.
""" """
log.debug(u'getImage %s' % name) log.debug(u'getImage %s' % path)
image = self._cache[name] image = self._cache[(path, source)]
if image.image is None: if image.image is None:
self._conversionQueue.modify_priority(image, Priority.High) self._conversionQueue.modify_priority(image, Priority.High)
# make sure we are running and if not give it a kick # make sure we are running and if not give it a kick
@ -271,13 +276,13 @@ class ImageManager(QtCore.QObject):
self._conversionQueue.modify_priority(image, Priority.Low) self._conversionQueue.modify_priority(image, Priority.Low)
return image.image return image.image
def getImageBytes(self, name): def getImageBytes(self, path, source):
""" """
Returns the byte string for an image. If not present wait for the Returns the byte string for an image. If not present wait for the
background thread to process it. background thread to process it.
""" """
log.debug(u'getImageBytes %s' % name) log.debug(u'getImageBytes %s' % path)
image = self._cache[name] image = self._cache[(path, source)]
if image.image_bytes is None: if image.image_bytes is None:
self._conversionQueue.modify_priority(image, Priority.Urgent) self._conversionQueue.modify_priority(image, Priority.Urgent)
# make sure we are running and if not give it a kick # make sure we are running and if not give it a kick
@ -287,24 +292,22 @@ class ImageManager(QtCore.QObject):
time.sleep(0.1) time.sleep(0.1)
return image.image_bytes return image.image_bytes
def addImage(self, name, path, source, background): def addImage(self, path, source, background):
""" """
Add image to cache if it is not already there. Add image to cache if it is not already there.
""" """
log.debug(u'addImage %s:%s' % (name, path)) log.debug(u'addImage %s' % path)
if not name in self._cache: if not (path, source) in self._cache:
image = Image(name, path, source, background) image = Image(path, source, background)
self._cache[name] = image self._cache[(path, source)] = image
self._conversionQueue.put( self._conversionQueue.put(
(image.priority, image.secondary_priority, image)) (image.priority, image.secondary_priority, image))
else: # Check if the there are any images with the same path and check if the
image = self._cache[name] # timestamp has changed.
if os.path.isfile(path) and \ for image in self._cache.values():
image.timestamp != os.stat(path).st_mtime: if image.path == path and image.timestamp != os.stat(path).st_mtime:
image.path = path
image.timestamp = os.stat(path).st_mtime image.timestamp = os.stat(path).st_mtime
self._resetImage(image) self._resetImage(image)
log.debug(u'Image in cache %s:%s' % (name, path))
# We want only one thread. # We want only one thread.
if not self.imageThread.isRunning(): if not self.imageThread.isRunning():
self.imageThread.start() self.imageThread.start()

View File

@ -135,11 +135,10 @@ class Renderer(object):
else: else:
theme_data, main_rect, footer_rect = \ theme_data, main_rect, footer_rect = \
self._theme_dimensions[theme_name] self._theme_dimensions[theme_name]
#FIXME: REMOVE deleteImage() call which will be added soon.
# if No file do not update cache # if No file do not update cache
if theme_data.background_filename: if theme_data.background_filename:
self.image_manager.addImage(theme_data.theme_name, self.image_manager.addImage(theme_data.background_filename,
theme_data.background_filename, u'theme', self.image_manager.imageSource.Theme,
QtGui.QColor(theme_data.background_border_color)) QtGui.QColor(theme_data.background_border_color))
def pre_render(self, override_theme_data=None): def pre_render(self, override_theme_data=None):
@ -243,8 +242,8 @@ class Renderer(object):
serviceItem.raw_footer = FOOTER serviceItem.raw_footer = FOOTER
# if No file do not update cache # if No file do not update cache
if theme_data.background_filename: if theme_data.background_filename:
self.image_manager.addImage(theme_data.theme_name, self.image_manager.addImage(theme_data.background_filename,
theme_data.background_filename, u'theme', self.image_manager.imageSource.Theme,
QtGui.QColor(theme_data.background_border_color)) QtGui.QColor(theme_data.background_border_color))
theme_data, main, footer = self.pre_render(theme_data) theme_data, main, footer = self.pre_render(theme_data)
serviceItem.themedata = theme_data serviceItem.themedata = theme_data

View File

@ -217,7 +217,8 @@ class ServiceItem(object):
self.image_border = background self.image_border = background
self.service_item_type = ServiceItemType.Image self.service_item_type = ServiceItemType.Image
self._raw_frames.append({u'title': title, u'path': path}) self._raw_frames.append({u'title': title, u'path': path})
self.renderer.image_manager.addImage(title, path, u'image', self.renderer.image_manager.addImage(path,
self.renderer.image_manager.imageSource.ImagePlugin,
self.image_border) self.image_border)
self._new_item() self._new_item()
@ -432,13 +433,12 @@ class ServiceItem(object):
def get_rendered_frame(self, row): def get_rendered_frame(self, row):
""" """
Returns the correct frame for a given list and Returns the correct frame for a given list and renders it if required.
renders it if required.
""" """
if self.service_item_type == ServiceItemType.Text: if self.service_item_type == ServiceItemType.Text:
return self._display_frames[row][u'html'].split(u'\n')[0] return self._display_frames[row][u'html'].split(u'\n')[0]
elif self.service_item_type == ServiceItemType.Image: elif self.service_item_type == ServiceItemType.Image:
return self._raw_frames[row][u'title'] return self._raw_frames[row][u'path']
else: else:
return self._raw_frames[row][u'image'] return self._raw_frames[row][u'image']

View File

@ -274,31 +274,33 @@ class MainDisplay(Display):
self.setVisible(False) self.setVisible(False)
self.setGeometry(self.screen[u'size']) self.setGeometry(self.screen[u'size'])
def directImage(self, name, path, background): def directImage(self, path, background):
""" """
API for replacement backgrounds so Images are added directly to cache. API for replacement backgrounds so Images are added directly to cache.
""" """
self.imageManager.addImage(name, path, u'image', background) self.imageManager.addImage(path, self.imageManager.imageSource.ImagePlugin, background)
if hasattr(self, u'serviceItem'): if not hasattr(self, u'serviceItem'):
self.override[u'image'] = name return False
self.override[u'theme'] = self.serviceItem.themedata.theme_name self.override[u'image'] = path
self.image(name) self.override[u'theme'] = self.serviceItem.themedata.background_filename
# Update the preview frame. self.image(path)
if self.isLive: # Update the preview frame.
self.parent().updatePreview() if self.isLive:
return True self.parent().updatePreview()
return False return True
def image(self, name): def image(self, path):
""" """
Add an image as the background. The image has already been added to the Add an image as the background. The image has already been added to the
cache. cache.
``name`` ``path``
The name of the image to be displayed. The path to the image to be displayed. **Note**, the path is only
passed to identify the image. If the image has changed it has to be
re-added to the image manager.
""" """
log.debug(u'image to display') log.debug(u'image to display')
image = self.imageManager.getImageBytes(name) image = self.imageManager.getImageBytes(path, self.imageManager.imageSource.ImagePlugin)
self.controller.mediaController.video_reset(self.controller) self.controller.mediaController.video_reset(self.controller)
self.displayImage(image) self.displayImage(image)
@ -360,7 +362,7 @@ class MainDisplay(Display):
self.setVisible(True) self.setVisible(True)
return QtGui.QPixmap.grabWidget(self) return QtGui.QPixmap.grabWidget(self)
def buildHtml(self, serviceItem, image=None): def buildHtml(self, serviceItem, image_path=u''):
""" """
Store the serviceItem and build the new HTML from it. Add the Store the serviceItem and build the new HTML from it. Add the
HTML to the display HTML to the display
@ -377,20 +379,20 @@ class MainDisplay(Display):
Receiver.send_message(u'video_background_replaced') Receiver.send_message(u'video_background_replaced')
self.override = {} self.override = {}
# We have a different theme. # We have a different theme.
elif self.override[u'theme'] != serviceItem.themedata.theme_name: elif self.override[u'theme'] != serviceItem.themedata.background_filename:
Receiver.send_message(u'live_theme_changed') Receiver.send_message(u'live_theme_changed')
self.override = {} self.override = {}
else: else:
# replace the background # replace the background
background = self.imageManager. \ background = self.imageManager. \
getImageBytes(self.override[u'image']) getImageBytes(self.override[u'image'], self.imageManager.imageSource.ImagePlugin)
self.setTransparency(self.serviceItem.themedata.background_type == self.setTransparency(self.serviceItem.themedata.background_type ==
BackgroundType.to_string(BackgroundType.Transparent)) BackgroundType.to_string(BackgroundType.Transparent))
if self.serviceItem.themedata.background_filename: if self.serviceItem.themedata.background_filename:
self.serviceItem.bg_image_bytes = self.imageManager. \ self.serviceItem.bg_image_bytes = self.imageManager. \
getImageBytes(self.serviceItem.themedata.theme_name) getImageBytes(self.serviceItem.themedata.background_filename, self.imageManager.imageSource.Theme)
if image: if image_path:
image_bytes = self.imageManager.getImageBytes(image) image_bytes = self.imageManager.getImageBytes(image_path, self.imageManager.imageSource.ImagePlugin)
else: else:
image_bytes = None image_bytes = None
html = build_html(self.serviceItem, self.screen, self.isLive, html = build_html(self.serviceItem, self.screen, self.isLive,

View File

@ -861,8 +861,10 @@ class SlideController(Controller):
# If current slide set background to image # If current slide set background to image
if framenumber == slideno: if framenumber == slideno:
self.serviceItem.bg_image_bytes = \ self.serviceItem.bg_image_bytes = \
self.imageManager.getImageBytes(frame[u'title']) self.imageManager.getImageBytes(frame[u'path'],
image = self.imageManager.getImage(frame[u'title']) self.imageManager.imageSource.ImagePlugin)
image = self.imageManager.getImage(frame[u'path'],
self.imageManager.imageSource.ImagePlugin)
label.setPixmap(QtGui.QPixmap.fromImage(image)) label.setPixmap(QtGui.QPixmap.fromImage(image))
self.previewListWidget.setCellWidget(framenumber, 0, label) self.previewListWidget.setCellWidget(framenumber, 0, label)
slideHeight = width * (1 / self.ratio) slideHeight = width * (1 / self.ratio)
@ -1092,14 +1094,14 @@ class SlideController(Controller):
u'%s_slide' % self.serviceItem.name.lower(), u'%s_slide' % self.serviceItem.name.lower(),
[self.serviceItem, self.isLive, row]) [self.serviceItem, self.isLive, row])
else: else:
toDisplay = self.serviceItem.get_rendered_frame(row) to_display = self.serviceItem.get_rendered_frame(row)
if self.serviceItem.is_text(): if self.serviceItem.is_text():
self.display.text(toDisplay) self.display.text(to_display)
else: else:
if start: if start:
self.display.buildHtml(self.serviceItem, toDisplay) self.display.buildHtml(self.serviceItem, to_display)
else: else:
self.display.image(toDisplay) self.display.image(to_display)
# reset the store used to display first image # reset the store used to display first image
self.serviceItem.bg_image_bytes = None self.serviceItem.bg_image_bytes = None
self.updatePreview() self.updatePreview()

View File

@ -669,8 +669,9 @@ class ThemeManager(QtGui.QWidget):
self._writeTheme(theme, image_from, image_to) self._writeTheme(theme, image_from, image_to)
if theme.background_type == \ if theme.background_type == \
BackgroundType.to_string(BackgroundType.Image): BackgroundType.to_string(BackgroundType.Image):
self.mainwindow.imageManager.updateImageBorder(theme.theme_name, self.mainwindow.imageManager.updateImageBorder(
u'theme', QtGui.QColor(theme.background_border_color)) theme.background_filename,
self.mainwindow.imageManager.imageSource.Theme, QtGui.QColor(theme.background_border_color))
self.mainwindow.imageManager.processUpdates() self.mainwindow.imageManager.processUpdates()
self.loadThemes() self.loadThemes()

View File

@ -99,4 +99,4 @@ class ImagePlugin(Plugin):
background = QtGui.QColor(Settings().value(self.settingsSection background = QtGui.QColor(Settings().value(self.settingsSection
+ u'/background color', QtCore.QVariant(u'#000000'))) + u'/background color', QtCore.QVariant(u'#000000')))
self.liveController.imageManager.updateImagesBorder( self.liveController.imageManager.updateImagesBorder(
u'image', background) self.liveController.imageManager.imageSource.ImagePlugin, background)

View File

@ -229,8 +229,7 @@ class ImageMediaItem(MediaManagerItem):
bitem = self.listView.item(item.row()) bitem = self.listView.item(item.row())
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString()) filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
if os.path.exists(filename): if os.path.exists(filename):
name = os.path.split(filename)[1] if self.plugin.liveController.display.directImage(
if self.plugin.liveController.display.directImage(name,
filename, background): filename, background):
self.resetAction.setVisible(True) self.resetAction.setVisible(True)
else: else:

View File

@ -278,8 +278,7 @@ class MessageListener(object):
item = message[0] item = message[0]
log.debug(u'Startup called with message %s' % message) log.debug(u'Startup called with message %s' % message)
hide_mode = message[2] hide_mode = message[2]
file = os.path.join(item.get_frame_path(), file = os.path.join(item.get_frame_path(), item.get_frame_title())
item.get_frame_title())
self.handler = item.title self.handler = item.title
if self.handler == self.mediaitem.Automatic: if self.handler == self.mediaitem.Automatic:
self.handler = self.mediaitem.findControllerByType(file) self.handler = self.mediaitem.findControllerByType(file)