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