comparison cagou/core/image.py @ 460:b5e8e470f7f7

core (image): convert SVG images + better error handling: - when an SVG image is found, new backend `imageConvert` method is used to convert it to PNG - by default, 128x128 is used as dest size. - removed code to handle image without extension in filename, as it is now working with Kivy. - if texture is not updated after `texture_update` is called, an error is logged, a fallback image is used, and `on_error` event is dispatched
author Goffi <goffi@goffi.org>
date Sun, 19 Apr 2020 17:06:57 +0200
parents aa204c813f07
children 3c9ba4a694ef
comparison
equal deleted inserted replaced
459:72290ebfaa8b 460:b5e8e470f7f7
16 16
17 # You should have received a copy of the GNU Affero General Public License 17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. 18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 19
20 20
21 import mimetypes
22 from functools import partial
23 from kivy.uix import image as kivy_img
21 from sat.core import log as logging 24 from sat.core import log as logging
25 from sat.tools.common import data_format
26 from cagou import G
27
22 log = logging.getLogger(__name__) 28 log = logging.getLogger(__name__)
23 from kivy.uix import image as kivy_img
24 from kivy.core.image import Image as CoreImage
25 from kivy.resources import resource_find
26 import io
27 import PIL
28 29
29 30
30 class Image(kivy_img.Image): 31 class Image(kivy_img.Image):
31 """Image widget which accept source without extension""" 32 """Image widget which accept source without extension"""
33 SVG_CONVERT_EXTRA = {'width': 128, 'height': 128}
34
35 def __init__(self, **kwargs):
36 self.register_event_type('on_error')
37 super().__init__(**kwargs)
38
39 def _imageConvertCb(self, path):
40 self.source = path
32 41
33 def texture_update(self, *largs): 42 def texture_update(self, *largs):
34 if not self.source: 43 if self.source:
35 self.texture = None 44 if mimetypes.guess_type(self.source, strict=False)[0] == 'image/svg+xml':
36 else: 45 log.debug(f"Converting SVG image at {self.source} to PNG")
37 filename = resource_find(self.source) 46 G.host.bridge.imageConvert(
38 self._loops = 0 47 self.source,
39 if filename is None: 48 "",
40 return log.error('Image: Error reading file {filename}'. 49 data_format.serialise(self.SVG_CONVERT_EXTRA),
41 format(filename=self.source)) 50 "",
42 mipmap = self.mipmap 51 callback=self._imageConvertCb,
43 if self._coreimage is not None: 52 errback=partial(
44 self._coreimage.unbind(on_texture=self._on_tex_change) 53 G.host.errback,
45 try: 54 message=f"Can't load image at {self.source}: {{msg}}"
46 self._coreimage = ci = CoreImage(filename, mipmap=mipmap, 55 )
47 anim_delay=self.anim_delay, 56 )
48 keep_data=self.keep_data, 57 return
49 nocache=self.nocache)
50 except Exception:
51 # loading failed probably because of unmanaged extention,
52 # we try our luck with with PIL
53 try:
54 im = PIL.Image.open(filename)
55 ext = im.format.lower()
56 del im
57 # we can't use im.tobytes as it would use the
58 # internal decompressed representation from pillow
59 # and im.save would need processing to handle format
60 data = io.BytesIO(open(filename, "rb").read())
61 cache_filename = "{}.{}".format(filename,ext) # needed for kivy's Image to use cache
62 self._coreimage = ci = CoreImage(data, ext=ext,
63 filename=cache_filename, mipmap=mipmap,
64 anim_delay=self.anim_delay,
65 keep_data=self.keep_data,
66 nocache=self.nocache)
67 except Exception as e:
68 log.warning("Can't load image: {}".format(e))
69 self._coreimage = ci = None
70 58
71 if ci: 59 super().texture_update(*largs)
72 ci.bind(on_texture=self._on_tex_change) 60 if self.source and self.texture is None:
73 self.texture = ci.texture 61 log.warning(
62 f"Image {self.source} has not been imported correctly, replacing by "
63 f"empty one")
64 # FIXME: temporary image, to be replaced by something showing that something
65 # went wrong
66 self.source = G.host.app.expand(
67 "{media}/misc/borders/border_hollow_black.png")
68 self.dispatch('on_error', Exception(f"Can't load source {self.source}"))
69
70 def on_error(self, err):
71 pass
74 72
75 73
76 class AsyncImage(kivy_img.AsyncImage): 74 class AsyncImage(kivy_img.AsyncImage):
77 """AsyncImage which accept file:// schema""" 75 """AsyncImage which accept file:// schema"""
78 76