AvatarWin: Add SVG support.
This commit is contained in:
parent
ed8224a3a5
commit
d19046b5b1
1 changed files with 38 additions and 2 deletions
|
@ -11,6 +11,15 @@ try:
|
|||
except ImportError:
|
||||
HAS_PIL = False
|
||||
|
||||
try:
|
||||
import gi
|
||||
gi.require_version('Rsvg', '2.0')
|
||||
from gi.repository import Rsvg
|
||||
import cairo
|
||||
HAS_RSVG = True
|
||||
except (ImportError, ValueError):
|
||||
HAS_RSVG = False
|
||||
|
||||
from poezio.windows.base_wins import Win
|
||||
from poezio.theming import get_theme, to_curses_attr
|
||||
from poezio.xhtml import _parse_css_color
|
||||
|
@ -19,6 +28,26 @@ from poezio.config import config
|
|||
from typing import Tuple, Optional, Callable
|
||||
|
||||
|
||||
def render_from_svg(svg: bytes) -> Optional[Image.Image]:
|
||||
if not HAS_RSVG:
|
||||
return None
|
||||
try:
|
||||
handle = Rsvg.Handle.new_from_data(svg)
|
||||
dimensions = handle.get_dimensions()
|
||||
surface = cairo.ImageSurface(cairo.Format.ARGB32, dimensions.width, dimensions.height)
|
||||
context = cairo.Context(surface)
|
||||
handle.render_cairo(context)
|
||||
data = surface.get_data()
|
||||
image = Image.frombytes('RGBA', (dimensions.width, dimensions.height), data.tobytes())
|
||||
# This is required because Cairo uses a BGRA (in host endianess)
|
||||
# format, and PIL an ABGR (in byte order) format. Yes, this is
|
||||
# confusing.
|
||||
b, g, r, a = image.split()
|
||||
return Image.merge('RGB', (r, g, b))
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
class ImageWin(Win):
|
||||
"""
|
||||
A window which contains either an image or a border.
|
||||
|
@ -27,7 +56,7 @@ class ImageWin(Win):
|
|||
__slots__ = ('_image', '_display_avatar')
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._image = None # type: Optional[Image]
|
||||
self._image = None # type: Optional[Image.Image]
|
||||
Win.__init__(self)
|
||||
if config.get('image_use_half_blocks'):
|
||||
self._display_avatar = self._display_avatar_half_blocks # type: Callable[[int, int], None]
|
||||
|
@ -44,8 +73,15 @@ class ImageWin(Win):
|
|||
self._win.erase()
|
||||
if data is not None and HAS_PIL:
|
||||
image_file = BytesIO(data)
|
||||
try:
|
||||
try:
|
||||
image = Image.open(image_file)
|
||||
except OSError:
|
||||
# TODO: Make the caller pass the MIME type, so we don’t
|
||||
# have to try all renderers like that.
|
||||
image = render_from_svg(data)
|
||||
if image is None:
|
||||
raise
|
||||
except OSError:
|
||||
self._display_border()
|
||||
else:
|
||||
|
|
Loading…
Reference in a new issue