Refactor avatar publishing

- Publish avatars with a size of 200x200
- Add AvatarSize.PUBLISH so we can easily change it in the future
- Dont upscale small avatars on publish
- Use surfaces for displaying the avatar in ProfileWindow and VcardWindow
because this scales correctly on HiDPI screens
This commit is contained in:
Philipp Hörist 2018-05-20 01:03:22 +02:00
parent cc874227a1
commit 2636e3449f
7 changed files with 56 additions and 27 deletions

View File

@ -33,9 +33,9 @@ class AvatarSize(IntEnum):
ROSTER = 32
CHAT = 48
NOTIFICATION = 48
PROFILE = 64
TOOLTIP = 125
VCARD = 200
PUBLISH = 200
class ArchiveState(IntEnum):
NEVER = 0

View File

@ -768,9 +768,7 @@ class GroupchatControl(ChatControlBase):
def _on_upload_avatar(self, action, param):
def _on_accept(filename):
with open(filename, 'rb') as file:
data = file.read()
sha = app.interface.save_avatar(data, publish=True)
sha = app.interface.save_avatar(filename, publish=True)
if sha is None:
dialogs.ErrorDialog(
_('Could not load image'),

View File

@ -440,11 +440,22 @@ def scale_with_ratio(size, width, height):
return size, size
if height > width:
ratio = height / float(width)
return int(size / ratio), size
return int(size / ratio), size
else:
ratio = width / float(height)
return size, int(size / ratio)
def scale_pixbuf(pixbuf, size):
width, height = scale_with_ratio(size,
pixbuf.get_width(),
pixbuf.get_height())
return pixbuf.scale_simple(width, height,
GdkPixbuf.InterpType.BILINEAR)
def scale_pixbuf_from_data(data, size):
pixbuf = get_pixbuf_from_data(data)
return scale_pixbuf(pixbuf, size)
def on_avatar_save_as_menuitem_activate(widget, avatar, default_name=''):
from gajim import dialogs
def on_continue(response, file_path):

View File

@ -2400,16 +2400,36 @@ class Interface:
UpdateGCAvatarEvent(None, contact=contact))
def save_avatar(self, data, publish=False):
"""
Save an avatar to the harddisk
:param data: publish=False data must be bytes
publish=True data must be a path to a file
:param publish: If publish is True, the method scales the file
to AvatarSize.PUBLISH size before saving
returns SHA1 value of the avatar or None on error
"""
if data is None:
return
if publish:
with open(data, 'rb') as file:
data = file.read()
pixbuf = gtkgui_helpers.get_pixbuf_from_data(data)
if pixbuf is None:
return
pixbuf = pixbuf.scale_simple(AvatarSize.PROFILE,
AvatarSize.PROFILE,
GdkPixbuf.InterpType.BILINEAR)
width = pixbuf.get_width()
height = pixbuf.get_height()
if width > AvatarSize.PUBLISH or height > AvatarSize.PUBLISH:
# Scale only down, never up
width, height = gtkgui_helpers.scale_with_ratio(
AvatarSize.PUBLISH, width, height)
pixbuf = pixbuf.scale_simple(width,
height,
GdkPixbuf.InterpType.BILINEAR)
publish_path = os.path.join(
configpaths.get('AVATAR'), 'temp_publish')
pixbuf.savev(publish_path, 'png', [], [])

View File

@ -124,9 +124,7 @@ class ProfileWindow:
def on_set_avatar_button_clicked(self, widget):
def on_ok(path_to_file):
with open(path_to_file, 'rb') as file:
data = file.read()
sha = app.interface.save_avatar(data, publish=True)
sha = app.interface.save_avatar(path_to_file, publish=True)
if sha is None:
dialogs.ErrorDialog(
_('Could not load image'), transient_for=self.window)
@ -224,13 +222,16 @@ class ProfileWindow:
self.avatar_sha = hashlib.sha1(photo_decoded).hexdigest()
if 'TYPE' in vcard_[i]:
self.avatar_mime_type = vcard_[i]['TYPE']
pixbuf = gtkgui_helpers.get_pixbuf_from_data(photo_decoded)
if pixbuf is None:
continue
pixbuf = pixbuf.scale_simple(
AvatarSize.PROFILE, AvatarSize.PROFILE,
GdkPixbuf.InterpType.BILINEAR)
image.set_from_pixbuf(pixbuf)
scale = self.window.get_scale_factor()
surface = app.interface.get_avatar(
self.avatar_sha, AvatarSize.VCARD, scale)
if surface is None:
pixbuf = gtkgui_helpers.scale_pixbuf_from_data(
photo_decoded, AvatarSize.VCARD)
surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf,
scale)
image.set_from_surface(surface)
button.show()
remove_avatar.show()
text_button.hide()

View File

@ -825,9 +825,7 @@ class SignalObject(dbus.service.Object):
else:
invalid_file = True
if not invalid_file and filesize < 16384:
with open(picture, 'rb') as fd:
data = fd.read()
sha = app.interface.save_avatar(data, publish=True)
sha = app.interface.save_avatar(picture, publish=True)
if sha is None:
return
app.config.set_per('accounts', self.name, 'avatar_sha', sha)

View File

@ -218,16 +218,17 @@ class VcardWindow:
except binascii.Error as error:
app.log('avatar').warning('Invalid avatar for %s: %s', jid, error)
continue
pixbuf = gtkgui_helpers.get_pixbuf_from_data(photo_decoded)
if pixbuf is None:
continue
pixbuf = pixbuf.scale_simple(
AvatarSize.PROFILE, AvatarSize.PROFILE,
GdkPixbuf.InterpType.BILINEAR)
image = self.xml.get_object('PHOTO_image')
image.set_from_pixbuf(pixbuf)
image.show()
self.avatar = pixbuf
pixbuf = gtkgui_helpers.scale_pixbuf(pixbuf, AvatarSize.VCARD)
surface = Gdk.cairo_surface_create_from_pixbuf(
pixbuf, self.window.get_scale_factor())
image = self.xml.get_object('PHOTO_image')
image.set_from_surface(surface)
image.show()
self.xml.get_object('user_avatar_label').show()
continue
if i in ('ADR', 'TEL', 'EMAIL'):