openlp/openlp/core/lib/imagemanager.py

172 lines
6.3 KiB
Python

# -*- 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