# -*- coding: utf-8 -*- # vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 ############################################################################### # OpenLP - Open Source Lyrics Projection # # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan # # Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, # # Armin Köhler, Joshua Millar, Stevan Pettit, Andreas Preikschat, Mattias # # Põldaru, Christian Richter, Philip Ridout, Jeffrey Smith, Maikel # # Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # # Software Foundation; version 2 of the License. # # # # This program is distributed in the hope that it will be useful, but WITHOUT # # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # # more details. # # # # You should have received a copy of the GNU General Public License along # # with this program; if not, write to the Free Software Foundation, Inc., 59 # # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ Provides the store and management for Images automatically caching them and resizing them when needed. Only one copy of each image is needed in the system. A Thread is used to convert the image to a byte array so the user does not need to wait for the conversion to happen. """ import logging import time from PyQt4 import QtCore from openlp.core.lib import resize_image, image_to_byte from openlp.core.ui import ScreenList log = logging.getLogger(__name__) class ImageThread(QtCore.QThread): """ A special Qt thread class to speed up the display of text based frames. This is threaded so it loads the frames in background """ def __init__(self, manager): QtCore.QThread.__init__(self, None) self.imageManager = manager def run(self): """ Run the thread. """ self.imageManager.process() class Image(object): name = '' path = '' dirty = True image = None image_bytes = None class ImageManager(QtCore.QObject): """ Image Manager handles the conversion and sizing of images. """ log.info(u'Image Manager loaded') def __init__(self): QtCore.QObject.__init__(self) current_screen = ScreenList.get_instance().current self.width = current_screen[u'size'].width() self.height = current_screen[u'size'].height() self._cache = {} self._thread_running = False self._cache_dirty = False self.image_thread = ImageThread(self) def update_display(self): """ Screen has changed size so rebuild the cache to new size """ log.debug(u'update_display') current_screen = ScreenList.get_instance().current self.width = current_screen[u'size'].width() self.height = current_screen[u'size'].height() # mark the images as dirty for a rebuild for key in self._cache.keys(): image = self._cache[key] image.dirty = True image.image = resize_image(image.path, self.width, self.height) self._cache_dirty = True # only one thread please if not self._thread_running: self.image_thread.start() def get_image(self, name): """ Return the Qimage from the cache """ log.debug(u'get_image %s' % name) return self._cache[name].image def get_image_bytes(self, name): """ Returns the byte string for an image If not present wait for the background thread to process it. """ log.debug(u'get_image_bytes %s' % name) if not self._cache[name].image_bytes: while self._cache[name].dirty: log.debug(u'get_image_bytes - waiting') time.sleep(0.1) return self._cache[name].image_bytes def del_image(self, name): """ Delete the Image from the Cache """ log.debug(u'del_image %s' % name) if name in self._cache: del self._cache[name] def add_image(self, name, path): """ Add image to cache if it is not already there """ log.debug(u'add_image %s:%s' % (name, path)) if not name in self._cache: image = Image() image.name = name image.path = path image.image = resize_image(path, self.width, self.height) self._cache[name] = image else: log.debug(u'Image in cache %s:%s' % (name, path)) self._cache_dirty = True # only one thread please if not self._thread_running: self.image_thread.start() def process(self): """ Controls the processing called from a QThread """ log.debug(u'process - started') self._thread_running = True self.clean_cache() # data loaded since we started ? while self._cache_dirty: log.debug(u'process - recycle') self.clean_cache() self._thread_running = False log.debug(u'process - ended') def clean_cache(self): """ Actually does the work. """ log.debug(u'clean_cache') # we will clean the cache now self._cache_dirty = False for key in self._cache.keys(): image = self._cache[key] if image.dirty: image.image_bytes = image_to_byte(image.image) image.dirty = False