diff --git a/gajim/common/const.py b/gajim/common/const.py index 4125ea1c8..d7ee4578e 100644 --- a/gajim/common/const.py +++ b/gajim/common/const.py @@ -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 diff --git a/gajim/groupchat_control.py b/gajim/groupchat_control.py index 21a60fc90..8cc2b5385 100644 --- a/gajim/groupchat_control.py +++ b/gajim/groupchat_control.py @@ -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'), diff --git a/gajim/gtkgui_helpers.py b/gajim/gtkgui_helpers.py index 3a6fd0c2b..36e254674 100644 --- a/gajim/gtkgui_helpers.py +++ b/gajim/gtkgui_helpers.py @@ -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): diff --git a/gajim/gui_interface.py b/gajim/gui_interface.py index 6b72e8217..3006f8d0a 100644 --- a/gajim/gui_interface.py +++ b/gajim/gui_interface.py @@ -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', [], []) diff --git a/gajim/profile_window.py b/gajim/profile_window.py index 7469ccd2c..05edbb4ae 100644 --- a/gajim/profile_window.py +++ b/gajim/profile_window.py @@ -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() diff --git a/gajim/remote_control.py b/gajim/remote_control.py index 8a9aa8931..856f4c9dc 100644 --- a/gajim/remote_control.py +++ b/gajim/remote_control.py @@ -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) diff --git a/gajim/vcard.py b/gajim/vcard.py index 0e5b81e05..dceefa901 100644 --- a/gajim/vcard.py +++ b/gajim/vcard.py @@ -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'):