1
# Miro - an RSS based video player application
2
# Copyright (C) 2005-2010 Participatory Culture Foundation
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU General Public License for more details.
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
# In addition, as a special exception, the copyright holders give
19
# permission to link the code of portions of this program with the OpenSSL
22
# You must obey the GNU General Public License in all respects for all of
23
# the code used other than OpenSSL. If you modify file(s) with this
24
# exception, you may extend this exception to your version of the file(s),
25
# but you are not obligated to do so. If you do not wish to do so, delete
26
# this exception statement from your version. If you delete this exception
27
# statement from all source files in the program, then also delete it here.
29
"""``miro.frontends.widgets.imagepool`` -- Get Image objects for image
32
imagepool handles creating Image and ImageSurface objects for image
33
filenames. It remembers images that have been created, and doesn't
34
create duplicate Image/ImageSurface objects for a single path.
41
from miro.plat import resources
42
from miro.plat.frontends.widgets import widgetset
44
# path_to_image and path_to_surface maps (path, size) tuples to
45
# Image/ImageSurface objects.
46
# Uses weak references so that once the Image/ImageSurface is not being used
48
path_to_image = weakref.WeakValueDictionary()
49
path_to_surface = weakref.WeakValueDictionary()
51
broken_image = widgetset.Image(resources.path('images/broken-image.gif'))
53
def scaled_size(image, size):
54
"""Takes an image which has a width and a height and a size tuple
55
that specifies the space available and returns the new width
56
and height that allows the image to fit into the sized space
57
at the correct height/width ratio.
59
:param image: the Image (must have width and height properties)
60
:param size: (width, height) tuple of space you want the image
63
if image.width == 0 or image.height == 0:
65
image_ratio = float(image.width) / image.height
66
new_ratio = float(size[0]) / size[1]
67
if image_ratio == new_ratio:
69
elif image_ratio > new_ratio:
70
# The scaled image has a wider aspect ratio than the old one.
71
height = int(round(float(size[0]) / image.width * image.height))
72
return size[0], height
74
# The scaled image has a taller aspect ratio than the old one.
75
width = int(round(float(size[1]) / image.height * image.width))
78
def get(path, size=None):
79
"""Returns an Image for path.
81
:param path: the filename for the image
82
:param size: if the image needs to fit into a specified sized
83
space, then specify this and get will return a
84
scaled image; if size is not specified, then this
85
returns the default sized image
88
return path_to_image[(path, size)]
91
image = widgetset.Image(path)
93
logging.warn("error loading image %s:\n%s", path,
94
traceback.format_exc())
97
image = image.resize(*scaled_size(image, size))
98
path_to_image[(path, size)] = image
100
path_to_image[(path, None)] = image
101
path_to_image[(path, (image.width, image.height))] = image
104
def get_surface(path, size=None):
105
"""Returns an ImageSurface for path.
107
:param path: the filename for the image
108
:param size: if the image needs to fit into a specified sized
109
space, then specify this and get will return a
110
scaled image; if size is not specified, then this
111
returns the default sized image
114
return path_to_surface[(path, size)]
116
image = get(path, size)
117
surface = widgetset.ImageSurface(image)
118
path_to_surface[(path, size)] = surface
120
path_to_surface[(path, (image.width, image.height))] = surface
123
class LazySurface(object):
124
"""Lazily loaded ImageSurface.
126
LazySurface objects only create ImageSurfaces as needed. If multiple
127
LazySurface objects are created for the same path, then they will share
128
the underlying ImageSurface object.
130
def __init__(self, path, size=None):
133
self._get_surface_if_available()
135
def _get_surface_if_available(self):
136
"""Try to get the ImageSurface for this object if it's already
137
created. This ensures that if the other ImageSurface is destroyed, we
138
will still have a reference.
141
self._surface = path_to_surface[(self.path, self.size)]
145
def _ensure_surface(self):
146
if not hasattr(self, '_surface'):
147
self._surface = get_surface(self.path, self.size)
150
self._ensure_surface()
151
return self._surface.width
152
width = property(get_width)
154
def get_height(self):
155
self._ensure_surface()
156
return self._surface.height
157
height = property(get_height)
159
def draw(self, context, x, y, width, height, fraction=1.0):
160
self._ensure_surface()
161
self._surface.draw(context, x, y, width, height, fraction)