0
|
1 |
# Copyright (c) 2005-2009 Nokia Corporation
|
|
2 |
#
|
|
3 |
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4 |
# you may not use this file except in compliance with the License.
|
|
5 |
# You may obtain a copy of the License at
|
|
6 |
#
|
|
7 |
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8 |
#
|
|
9 |
# Unless required by applicable law or agreed to in writing, software
|
|
10 |
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11 |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12 |
# See the License for the specific language governing permissions and
|
|
13 |
# limitations under the License.
|
|
14 |
|
|
15 |
import e32
|
|
16 |
import _graphics
|
|
17 |
import sysinfo
|
|
18 |
|
|
19 |
Draw=_graphics.Draw
|
|
20 |
|
|
21 |
def _revdict(d):
|
|
22 |
return dict([(d[k],k) for k in d.keys()])
|
|
23 |
|
|
24 |
SDK12=not hasattr(_graphics,'FLIP_LEFT_RIGHT')
|
|
25 |
|
|
26 |
if not SDK12:
|
|
27 |
FLIP_LEFT_RIGHT=_graphics.FLIP_LEFT_RIGHT
|
|
28 |
FLIP_TOP_BOTTOM=_graphics.FLIP_TOP_BOTTOM
|
|
29 |
ROTATE_90=_graphics.ROTATE_90
|
|
30 |
ROTATE_180=_graphics.ROTATE_180
|
|
31 |
ROTATE_270=_graphics.ROTATE_270
|
|
32 |
|
|
33 |
class Image(object):
|
|
34 |
_twips = sysinfo.display_twips()
|
|
35 |
_pixels = sysinfo.display_pixels()
|
|
36 |
_default_density = (float(_twips[0])/_pixels[0],
|
|
37 |
float(_twips[1])/_pixels[1])
|
|
38 |
_modemap={'1': _graphics.EGray2,
|
|
39 |
'L': _graphics.EGray256,
|
|
40 |
'RGB12': _graphics.EColor4K,
|
|
41 |
'RGB16': _graphics.EColor64K,
|
|
42 |
'RGB': _graphics.EColor16M}
|
|
43 |
_moderevmap=_revdict(_modemap)
|
|
44 |
def __init__(self,img):
|
|
45 |
self._image=img
|
|
46 |
if img.twipsize == (0,0):
|
|
47 |
img.twipsize = (self._default_density[0]*img.size[0],self._default_density[1]*img.size[1])
|
|
48 |
self._drawapi=self._image._drawapi
|
|
49 |
self._draw=_graphics.Draw(self._image)
|
|
50 |
self._bitmapapi=self._image._bitmapapi
|
|
51 |
self.getpixel=self._image.getpixel
|
|
52 |
self._lock=None
|
|
53 |
self._errcode=0
|
|
54 |
self._waiting=0
|
|
55 |
self._resized_image=None
|
|
56 |
for k in _graphics._draw_methods:
|
|
57 |
setattr(self,k,getattr(self._draw,k))
|
|
58 |
size=property(lambda self:self._image.size)
|
|
59 |
mode=property(lambda self:self._moderevmap[self._image.mode])
|
|
60 |
|
|
61 |
twipsize=property(lambda self: self._image.twipsize,
|
|
62 |
lambda self, value: setattr(self._image,
|
|
63 |
"twipsize",
|
|
64 |
value))
|
|
65 |
def from_cfbsbitmap(bitmap):
|
|
66 |
return Image(_graphics.ImageFromCFbsBitmap(bitmap))
|
|
67 |
from_cfbsbitmap=staticmethod(from_cfbsbitmap)
|
|
68 |
def from_icon(filename,image_id,size):
|
|
69 |
if e32.s60_version_info>=(3,0):
|
|
70 |
return Image(_graphics.ImageFromIcon(filename,image_id,size[0],size[1]))
|
|
71 |
else:
|
|
72 |
raise RuntimeError('not supported')
|
|
73 |
from_icon=staticmethod(from_icon)
|
|
74 |
def new(size,mode='RGB16'):
|
|
75 |
if not Image._modemap.has_key(mode):
|
|
76 |
raise ValueError('invalid mode')
|
|
77 |
return Image(_graphics.ImageNew(size,Image._modemap[mode]))
|
|
78 |
new=staticmethod(new)
|
|
79 |
if not SDK12:
|
|
80 |
def open(filename):
|
|
81 |
def finish_load(errcode):
|
|
82 |
img._errcode=errcode
|
|
83 |
lock.signal()
|
|
84 |
lock=e32.Ao_lock()
|
|
85 |
img=Image(_graphics.ImageOpen(unicode(filename),finish_load))
|
|
86 |
lock.wait()
|
|
87 |
if img._errcode != 0:
|
|
88 |
raise SymbianError,(img._errcode,
|
|
89 |
"Error loading image:"+e32.strerror(img._errcode))
|
|
90 |
return img
|
|
91 |
open=staticmethod(open)
|
|
92 |
def inspect(filename):
|
|
93 |
(size,mode)=_graphics.ImageInspect(unicode(filename))
|
|
94 |
return {'size': size}
|
|
95 |
inspect=staticmethod(inspect)
|
|
96 |
def load(self,filename,callback=None):
|
|
97 |
self._wait()
|
|
98 |
self._filename=unicode(filename)
|
|
99 |
self._usercallback=callback
|
|
100 |
self._lock=e32.Ao_lock()
|
|
101 |
self._image.load(self._filename,self._callback)
|
|
102 |
if callback is None:
|
|
103 |
self._wait()
|
|
104 |
if self._errcode != 0:
|
|
105 |
err=self._errcode
|
|
106 |
self._errcode=0
|
|
107 |
raise SymbianError,(err, "Error loading image:"+e32.strerror(err))
|
|
108 |
def save(self,filename,callback=None,format=None,quality=75,bpp=24,compression='default'):
|
|
109 |
if format is None:
|
|
110 |
if filename.lower().endswith('.jpg') or filename.lower().endswith('.jpeg'):
|
|
111 |
format='JPEG'
|
|
112 |
elif filename.lower().endswith('.png'):
|
|
113 |
format='PNG'
|
|
114 |
else:
|
|
115 |
raise ValueError('unrecognized suffix and format not specified')
|
|
116 |
self._wait()
|
|
117 |
lock=e32.Ao_lock()
|
|
118 |
self._image.save(unicode(filename),self._callback,format,quality,compression,bpp)
|
|
119 |
# If the code above didn't raise an exception, this method
|
|
120 |
# will succeed, so now it's safe to modify object state.
|
|
121 |
self._usercallback=callback
|
|
122 |
self._lock=lock
|
|
123 |
if callback is None:
|
|
124 |
self._wait()
|
|
125 |
if self._errcode != 0:
|
|
126 |
err=self._errcode
|
|
127 |
self._errcode=0
|
|
128 |
raise SymbianError,(err, "Error saving image:" + e32.strerror(err))
|
|
129 |
def resize(self,size,callback=None,keepaspect=0):
|
|
130 |
self._wait()
|
|
131 |
newimage=Image.new(size,self.mode)
|
|
132 |
lock=e32.Ao_lock()
|
|
133 |
self._image.resize(newimage,keepaspect,self._callback)
|
|
134 |
# If the code above didn't raise an exception, this method
|
|
135 |
# will succeed, so now it's safe to modify object state.
|
|
136 |
self._lock=lock
|
|
137 |
self._usercallback=callback
|
|
138 |
self._resized_image=newimage
|
|
139 |
if callback is None:
|
|
140 |
self._wait()
|
|
141 |
if self._errcode != 0:
|
|
142 |
err=self._errcode
|
|
143 |
self._errcode=0
|
|
144 |
raise SymbianError,(err, "Error resizing image:"+e32.strerror(err))
|
|
145 |
t=self._resized_image
|
|
146 |
self._resized_image=None
|
|
147 |
return t
|
|
148 |
def transpose(self,direction,callback=None):
|
|
149 |
self._wait()
|
|
150 |
if direction == ROTATE_90 or direction == ROTATE_270:
|
|
151 |
newsize=(self.size[1],self.size[0])
|
|
152 |
else:
|
|
153 |
newsize=self.size
|
|
154 |
newimage=Image.new(newsize,self.mode)
|
|
155 |
lock=e32.Ao_lock()
|
|
156 |
self._image.transpose(newimage,direction,self._callback)
|
|
157 |
# If the code above didn't raise an exception, this method
|
|
158 |
# will succeed, so now it's safe to modify object state.
|
|
159 |
self._lock=lock
|
|
160 |
self._usercallback=callback
|
|
161 |
self._resized_image=newimage
|
|
162 |
if callback is None:
|
|
163 |
self._wait()
|
|
164 |
if self._errcode != 0:
|
|
165 |
err=self._errcode
|
|
166 |
self._errcode=0
|
|
167 |
raise RuntimeError("Error resizing image:"+str(err))
|
|
168 |
t=self._resized_image
|
|
169 |
self._resized_image=None
|
|
170 |
return t
|
|
171 |
def _callback(self, errcode):
|
|
172 |
self._errcode=errcode
|
|
173 |
if self._lock:
|
|
174 |
self._lock.signal()
|
|
175 |
self._lock=None
|
|
176 |
if self._usercallback is not None:
|
|
177 |
t=self._usercallback
|
|
178 |
self._usercallback=None
|
|
179 |
if self._resized_image is not None: # resize in progress
|
|
180 |
if self._errcode == 0:
|
|
181 |
newimage=self._resized_image
|
|
182 |
self._resized_image=None
|
|
183 |
t(newimage)
|
|
184 |
else:
|
|
185 |
t(None)
|
|
186 |
else:
|
|
187 |
t(self._errcode)
|
|
188 |
def _wait(self):
|
|
189 |
if self._lock:
|
|
190 |
if self._waiting:
|
|
191 |
raise RuntimeError("Image object busy.")
|
|
192 |
self._waiting=1
|
|
193 |
self._lock.wait()
|
|
194 |
self._waiting=0
|
|
195 |
def stop(self):
|
|
196 |
self._image.stop()
|
|
197 |
if self._lock:
|
|
198 |
self._errcode=0
|
|
199 |
self._lock.signal()
|
|
200 |
self._lock=None
|
|
201 |
|
|
202 |
def screenshot():
|
|
203 |
return Image(_graphics.screenshot())
|
|
204 |
|
|
205 |
|
|
206 |
FONT_BOLD=1
|
|
207 |
FONT_ITALIC=2
|
|
208 |
FONT_SUBSCRIPT=4
|
|
209 |
FONT_SUPERSCRIPT=8
|
|
210 |
FONT_ANTIALIAS=16
|
|
211 |
FONT_NO_ANTIALIAS=32
|
|
212 |
|
|
213 |
__all__=('Draw',
|
|
214 |
'Image',
|
|
215 |
'screenshot',
|
|
216 |
'FONT_BOLD',
|
|
217 |
'FONT_ITALIC',
|
|
218 |
'FONT_SUBSCRIPT',
|
|
219 |
'FONT_SUPERSCRIPT',
|
|
220 |
'FONT_ANTIALIAS',
|
|
221 |
'FONT_NO_ANTIALIAS')
|
|
222 |
|
|
223 |
if not SDK12:
|
|
224 |
__all__+=(('FLIP_LEFT_RIGHT',
|
|
225 |
'FLIP_TOP_BOTTOM',
|
|
226 |
'ROTATE_90',
|
|
227 |
'ROTATE_180',
|
|
228 |
'ROTATE_270'))
|
|
229 |
|