blob: 468399bb7e5c4ddc4fc020f418fff9cd812158e6 [file] [log] [blame]
Stepan Salenikovich6f687072015-03-26 10:43:37 -04001/*
Stepan Salenikovichbe87d2c2016-01-25 14:14:34 -05002 * Copyright (C) 2015-2016 Savoir-faire Linux Inc.
Stepan Salenikovich6f687072015-03-26 10:43:37 -04003 * Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Stepan Salenikovich6f687072015-03-26 10:43:37 -040018 */
19
Stepan Salenikovichbbd6c132015-08-20 15:21:48 -040020#include "pixbufmanipulator.h"
Stepan Salenikovich6f687072015-03-26 10:43:37 -040021
22#include "../utils/drawing.h"
23#include <QtCore/QSize>
24#include <QtCore/QMetaType>
25#include <person.h>
26#include <memory>
27#include <call.h>
28#include <contactmethod.h>
29
Stepan Salenikovichbbd6c132015-08-20 15:21:48 -040030namespace Interfaces {
31
32PixbufManipulator::PixbufManipulator()
33 : fallbackAvatar_{ring_draw_fallback_avatar(FALLBACK_AVATAR_SIZE), g_object_unref}
Stepan Salenikovichee8506e2015-08-13 11:35:14 -040034 , conferenceAvatar_{ring_draw_conference_avatar(FALLBACK_AVATAR_SIZE), g_object_unref}
Stepan Salenikovich6f687072015-03-26 10:43:37 -040035{
36}
37
38std::shared_ptr<GdkPixbuf>
Stepan Salenikovichbbd6c132015-08-20 15:21:48 -040039PixbufManipulator::scaleAndFrame(const GdkPixbuf *photo, const QSize& size)
Stepan Salenikovich6f687072015-03-26 10:43:37 -040040{
41 /**
42 * for now, respect the height requested
43 * the framing process will add another 10px, so account for that
44 * when scaling the photos
45 */
46
47 int height = size.height();
48 if (size.height() != size.width())
49 g_warning("requested contact photo width != height; only respecting the height as the largest dimension");
50 int photo_h = height - 10;
51 int photo_w = photo_h;
52
53 /* scale photo, make sure to respect the request height as the largest dimension*/
54 int w = gdk_pixbuf_get_width(photo);
55 int h = gdk_pixbuf_get_height(photo);
56 if (h > w)
57 photo_w = w * ((double)photo_h / h);
58 if (w > h)
59 photo_h = h * ((double)photo_w / w);
60
61 std::unique_ptr<GdkPixbuf, decltype(g_object_unref)&> scaled_photo{
62 gdk_pixbuf_scale_simple(photo, photo_w, photo_h, GDK_INTERP_BILINEAR),
63 g_object_unref};
64
65 /* frame photo */
66 return {ring_frame_avatar(scaled_photo.get()), g_object_unref};
67}
68
69QVariant
Stepan Salenikovichbbd6c132015-08-20 15:21:48 -040070PixbufManipulator::callPhoto(Call* c, const QSize& size, bool displayPresence)
Stepan Salenikovich6f687072015-03-26 10:43:37 -040071{
Stepan Salenikovichee8506e2015-08-13 11:35:14 -040072 if (c->type() == Call::Type::CONFERENCE)
73 return QVariant::fromValue(scaleAndFrame(conferenceAvatar_.get(), size));
Stepan Salenikovich6f687072015-03-26 10:43:37 -040074 return callPhoto(c->peerContactMethod(), size, displayPresence);
75}
76
77QVariant
Stepan Salenikovichbbd6c132015-08-20 15:21:48 -040078PixbufManipulator::callPhoto(const ContactMethod* n, const QSize& size, bool displayPresence)
Stepan Salenikovich6f687072015-03-26 10:43:37 -040079{
80 if (n->contact()) {
81 return contactPhoto(n->contact(), size, displayPresence);
82 } else {
83 return QVariant::fromValue(scaleAndFrame(fallbackAvatar_.get(), size));
84 }
85}
86
87QVariant
Stepan Salenikovichbbd6c132015-08-20 15:21:48 -040088PixbufManipulator::contactPhoto(Person* c, const QSize& size, bool displayPresence)
Stepan Salenikovich6f687072015-03-26 10:43:37 -040089{
90 Q_UNUSED(displayPresence);
91
92 /**
93 * try to get the photo
94 * otherwise use the fallback avatar
95 */
96
97 std::shared_ptr<GdkPixbuf> photo;
98
99 if (c->photo().isValid())
100 photo = c->photo().value<std::shared_ptr<GdkPixbuf>>();
101 else
102 photo = fallbackAvatar_;
103
104 return QVariant::fromValue(scaleAndFrame(photo.get(), size));
105}
106
Stepan Salenikovichbbd6c132015-08-20 15:21:48 -0400107QVariant PixbufManipulator::personPhoto(const QByteArray& data, const QString& type)
Stepan Salenikovich6f687072015-03-26 10:43:37 -0400108{
109 Q_UNUSED(type);
110 /* Try to load the image from the data provided by lrc vcard utils;
111 * lrc is getting the image data assuming that it is inlined in the vcard,
112 * for now URIs are not supported.
113 *
114 * The format of the data should be either base 64 or ascii (hex), try both
115 */
116
117 GError *error = NULL;
118 GdkPixbuf *pixbuf = NULL;
119 GInputStream *stream = NULL;
120
121 /* first try using base64 */
122 QByteArray ba64 = QByteArray::fromBase64(data);
123 stream = g_memory_input_stream_new_from_data(ba64.constData(),
124 ba64.size(),
125 NULL);
126
127 pixbuf = gdk_pixbuf_new_from_stream(stream, NULL, &error);
128 g_input_stream_close(stream, NULL, NULL);
129 g_object_unref(stream);
130
131 if (!pixbuf) {
132 // g_debug("failed decoding person photo using base64: %s", error->message);
Stepan Salenikovich8a287fc2015-05-01 16:53:20 -0400133 g_clear_error(&error);
Stepan Salenikovich6f687072015-03-26 10:43:37 -0400134
135 /* failed with base64, try hex */
136 QByteArray baHex = QByteArray::fromHex(data);
137 stream = g_memory_input_stream_new_from_data(baHex.constData(),
138 baHex.size(),
139 NULL);
140
141 pixbuf = gdk_pixbuf_new_from_stream(stream, NULL, &error);
142 g_input_stream_close(stream, NULL, NULL);
143 g_object_unref(stream);
144
145 if (!pixbuf) {
146 // g_debug("failed decoding person photo using hex (ASCII): %s", error->message);
Stepan Salenikovich8a287fc2015-05-01 16:53:20 -0400147 g_clear_error(&error);
Stepan Salenikovich6f687072015-03-26 10:43:37 -0400148 }
149 }
150
151 if (pixbuf) {
152 std::shared_ptr<GdkPixbuf> avatar(pixbuf, g_object_unref);
153 return QVariant::fromValue(avatar);
154 }
155
156 /* could not load image, return emtpy QVariant */
157 return QVariant();
158}
Stepan Salenikovichbbd6c132015-08-20 15:21:48 -0400159
160QVariant
161PixbufManipulator::numberCategoryIcon(const QVariant& p, const QSize& size, bool displayPresence, bool isPresent)
162{
163 Q_UNUSED(p)
164 Q_UNUSED(size)
165 Q_UNUSED(displayPresence)
166 Q_UNUSED(isPresent)
167 return QVariant();
168}
169
170QVariant
171PixbufManipulator::securityIssueIcon(const QModelIndex& index)
172{
173 Q_UNUSED(index)
174 return QVariant();
175}
176
177QByteArray
178PixbufManipulator::toByteArray(const QVariant& pxm)
179{
180 Q_UNUSED(pxm);
181 return QByteArray();
182}
183
184QVariant
185PixbufManipulator::collectionIcon(const CollectionInterface* interface, PixmapManipulatorI::CollectionIconHint hint) const
186{
187 Q_UNUSED(interface)
188 Q_UNUSED(hint)
189 return QVariant();
190}
191QVariant
192PixbufManipulator::securityLevelIcon(const SecurityEvaluationModel::SecurityLevel level) const
193{
194 Q_UNUSED(level)
195 return QVariant();
196}
197QVariant
198PixbufManipulator::historySortingCategoryIcon(const CategorizedHistoryModel::SortedProxy::Categories cat) const
199{
200 Q_UNUSED(cat)
201 return QVariant();
202}
203QVariant
204PixbufManipulator::contactSortingCategoryIcon(const CategorizedContactModel::SortedProxy::Categories cat) const
205{
206 Q_UNUSED(cat)
207 return QVariant();
208}
209QVariant
210PixbufManipulator::userActionIcon(const UserActionElement& state) const
211{
212 Q_UNUSED(state)
213 return QVariant();
214}
215
Stepan Salenikovich8d076952016-01-08 13:48:43 -0500216QVariant PixbufManipulator::decorationRole(const QModelIndex& index)
217{
218 Q_UNUSED(index)
219 return QVariant();
220}
221
222QVariant PixbufManipulator::decorationRole(const Call* c)
223{
224 Q_UNUSED(c)
225 return QVariant();
226}
227
228QVariant PixbufManipulator::decorationRole(const ContactMethod* cm)
229{
230 Q_UNUSED(cm)
231 return QVariant();
232}
233
234QVariant PixbufManipulator::decorationRole(const Person* p)
235{
236 Q_UNUSED(p)
237 return QVariant();
238}
239
Alexandre Lision50fd6af2016-04-20 17:13:58 -0400240QVariant PixbufManipulator::decorationRole(const Account* p)
241{
242 Q_UNUSED(p)
243 return QVariant();
244}
245
Stepan Salenikovichbbd6c132015-08-20 15:21:48 -0400246} // namespace Interfaces