blob: 0862f20c063b17732e61cfe2973d3f6e2fe8aa09 [file] [log] [blame]
Alexandre Lision3b0bd332015-03-15 18:43:07 -04001/*
Alexandre Lision9fe374b2016-01-06 10:17:31 -05002 * Copyright (C) 2015-2016 Savoir-faire Linux Inc.
Alexandre Lision3b0bd332015-03-15 18:43:07 -04003 * Author: Alexandre Lision <alexandre.lision@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.
Alexandre Lision3b0bd332015-03-15 18:43:07 -040018 */
19#import "ImageManipulationDelegate.h"
20
21#import <Cocoa/Cocoa.h>
22#import <Foundation/Foundation.h>
23
24//Qt
25#import <QSize>
26#import <QBuffer>
27#import <QtGui/QColor>
28#import <QtGui/QPainter>
29#import <QtGui/QBitmap>
30#import <QtWidgets/QApplication>
31#import <QtGui/QImage>
32#import <QtMacExtras/qmacfunctions.h>
33#import <QtGui/QPalette>
34
35//Ring
36#import <person.h>
37#import <contactmethod.h>
Alexandre Lision3b0bd332015-03-15 18:43:07 -040038
Alexandre Lision7a166e42015-09-02 15:04:43 -040039namespace Interfaces {
Alexandre Lision3b0bd332015-03-15 18:43:07 -040040
Alexandre Lision7a166e42015-09-02 15:04:43 -040041 ImageManipulationDelegate::ImageManipulationDelegate()
42 {
Alexandre Lision3b0bd332015-03-15 18:43:07 -040043
Alexandre Lision7a166e42015-09-02 15:04:43 -040044 }
Alexandre Lision3b0bd332015-03-15 18:43:07 -040045
Alexandre Lision7a166e42015-09-02 15:04:43 -040046 QVariant ImageManipulationDelegate::contactPhoto(Person* c, const QSize& size, bool displayPresence) {
Alexandre Lisionde0314b2015-09-02 15:45:21 -040047 const int radius = size.height() / 2;
Alexandre Lision7a166e42015-09-02 15:04:43 -040048
49 QPixmap pxm;
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040050 if (c && c->photo().isValid()) {
Alexandre Lisionf02a32b2016-04-19 15:01:07 -040051 QPixmap contactPhoto(qvariant_cast<QPixmap>(c->photo()).scaled(size, Qt::KeepAspectRatioByExpanding,
52 Qt::SmoothTransformation));
53
54 QPixmap finalImg;
55 if (contactPhoto.size() != size) {
56 finalImg = crop(contactPhoto, size);
57 } else
58 finalImg = contactPhoto;
59
Alexandre Lision7a166e42015-09-02 15:04:43 -040060 pxm = QPixmap(size);
61 pxm.fill(Qt::transparent);
62 QPainter painter(&pxm);
63
64 //Clear the pixmap
Alexandre Lisionde0314b2015-09-02 15:45:21 -040065 painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
Alexandre Lision7a166e42015-09-02 15:04:43 -040066 painter.setCompositionMode(QPainter::CompositionMode_Clear);
67 painter.fillRect(0,0,size.width(),size.height(),QBrush(Qt::white));
68 painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
69
70 //Add corner radius to the Pixmap
Alexandre Lisionf02a32b2016-04-19 15:01:07 -040071 QRect pxRect = finalImg.rect();
Alexandre Lision7a166e42015-09-02 15:04:43 -040072 QBitmap mask(pxRect.size());
73 QPainter customPainter(&mask);
Alexandre Lisionde0314b2015-09-02 15:45:21 -040074 customPainter.setRenderHints (QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
Alexandre Lision7a166e42015-09-02 15:04:43 -040075 customPainter.fillRect (pxRect , Qt::white );
76 customPainter.setBackground (Qt::black );
77 customPainter.setBrush (Qt::black );
Alexandre Lisionf02a32b2016-04-19 15:01:07 -040078 customPainter.drawRoundedRect(pxRect,radius,radius );
79 finalImg.setMask (mask );
80 painter.drawPixmap (0,0,finalImg );
Alexandre Lisionde0314b2015-09-02 15:45:21 -040081 painter.setBrush (Qt::NoBrush );
82 painter.setPen (Qt::black );
83 painter.setCompositionMode (QPainter::CompositionMode_SourceIn);
84 painter.drawRoundedRect(0,0,pxm.height(),pxm.height(),radius,radius);
Alexandre Lision7a166e42015-09-02 15:04:43 -040085 }
86 else {
87 pxm = drawDefaultUserPixmap(size, false, false);
88 }
89
90 return pxm;
91 }
92
Alexandre Lisionf02a32b2016-04-19 15:01:07 -040093 QPixmap
94 ImageManipulationDelegate::crop(QPixmap& photo, const QSize& destSize)
95 {
96 auto initSize = photo.size();
97 float leftDelta = 0;
98 float topDelta = 0;
99
100 if (destSize.height() == initSize.height()) {
101 leftDelta = (destSize.width() - initSize.width()) / 2;
102 } else {
103 topDelta = (destSize.height() - initSize.height()) / 2;
104 }
105
106 float xScale = (float)destSize.width() / initSize.width();
107 float yScale = (float)destSize.height() / initSize.height();
108
109 QRectF destRect(leftDelta, topDelta,
110 initSize.width() - leftDelta, initSize.height() - topDelta);
111
112 destRect.setLeft(leftDelta * xScale);
113 destRect.setTop(topDelta * yScale);
114
115 destRect.setWidth((initSize.width() - leftDelta) * xScale);
116 destRect.setHeight((initSize.height() - topDelta) * yScale);
117
118 return photo.copy(destRect.toRect());
119 }
120
Alexandre Lision7a166e42015-09-02 15:04:43 -0400121 QVariant
122 ImageManipulationDelegate::callPhoto(Call* c, const QSize& size, bool displayPresence)
123 {
124 return callPhoto(c->peerContactMethod(), size, displayPresence);
125 }
126
127 QVariant
128 ImageManipulationDelegate::callPhoto(const ContactMethod* n, const QSize& size, bool displayPresence)
129 {
130 if (n->contact()) {
131 return contactPhoto(n->contact(), size, displayPresence);
132 } else {
133 return drawDefaultUserPixmap(size, false, false);
134 }
135 }
136
137 QVariant ImageManipulationDelegate::personPhoto(const QByteArray& data, const QString& type)
138 {
139 QImage image;
140 //For now, ENCODING is only base64 and image type PNG or JPG
141 const bool ret = image.loadFromData(QByteArray::fromBase64(data),type.toLatin1());
142 if (!ret)
143 qDebug() << "vCard image loading failed";
144
145 return QPixmap::fromImage(image);
146 }
147
148 QByteArray ImageManipulationDelegate::toByteArray(const QVariant& pxm)
149 {
150 //Preparation of our QPixmap
151 QByteArray bArray;
152 QBuffer buffer(&bArray);
153 buffer.open(QIODevice::WriteOnly);
154
155 //PNG ?
156 (qvariant_cast<QPixmap>(pxm)).save(&buffer, "PNG");
157 buffer.close();
158
159 return bArray;
160 }
161
162 QPixmap ImageManipulationDelegate::drawDefaultUserPixmap(const QSize& size, bool displayPresence, bool isPresent) {
Alexandre Lision7a166e42015-09-02 15:04:43 -0400163 // create the image somehow, load from file, draw into it...
Alexandre Lision4baba4c2016-02-11 13:00:57 -0500164 auto sourceImgRef = CGImageSourceCreateWithData((__bridge CFDataRef)[[NSImage imageNamed:@"default_user_icon"] TIFFRepresentation], NULL);
Alexandre Lision7a166e42015-09-02 15:04:43 -0400165 auto imgRef = CGImageSourceCreateImageAtIndex(sourceImgRef, 0, NULL);
Alexandre Lisionde0314b2015-09-02 15:45:21 -0400166 auto finalpxm = QtMac::fromCGImageRef(resizeCGImage(imgRef, size));
Alexandre Lision7a166e42015-09-02 15:04:43 -0400167 CFRelease(sourceImgRef);
168 CFRelease(imgRef);
Alexandre Lision3b0bd332015-03-15 18:43:07 -0400169
Alexandre Lisiond5229f32015-11-16 11:17:41 -0500170 return finalpxm;
Alexandre Lision3b0bd332015-03-15 18:43:07 -0400171 }
Alexandre Lision7a166e42015-09-02 15:04:43 -0400172
173 CGImageRef ImageManipulationDelegate::resizeCGImage(CGImageRef image, const QSize& size) {
174 // create context, keeping original image properties
Alexandre Lision7a166e42015-09-02 15:04:43 -0400175 CGContextRef context = CGBitmapContextCreate(NULL, size.width(), size.height(),
176 CGImageGetBitsPerComponent(image),
Alexandre Lisiond5229f32015-11-16 11:17:41 -0500177 CGImageGetBytesPerRow(image),
178 CGImageGetColorSpace(image),
179 kCGImageAlphaPremultipliedLast);
Alexandre Lision7a166e42015-09-02 15:04:43 -0400180
181 if(context == NULL)
182 return nil;
183
184 // draw image to context (resizing it)
185 CGContextDrawImage(context, CGRectMake(0, 0, size.width(), size.height()), image);
186 // extract resulting image from context
187 CGImageRef imgRef = CGBitmapContextCreateImage(context);
188 CGContextRelease(context);
189
190 return imgRef;
191 }
192
193 QVariant
194 ImageManipulationDelegate::numberCategoryIcon(const QVariant& p, const QSize& size, bool displayPresence, bool isPresent)
195 {
196 Q_UNUSED(p)
197 Q_UNUSED(size)
198 Q_UNUSED(displayPresence)
199 Q_UNUSED(isPresent)
200 return QVariant();
201 }
202
203 QVariant
204 ImageManipulationDelegate::securityIssueIcon(const QModelIndex& index)
205 {
206 Q_UNUSED(index)
207 return QVariant();
208 }
209
210 QVariant
211 ImageManipulationDelegate::collectionIcon(const CollectionInterface* interface, PixmapManipulatorI::CollectionIconHint hint) const
212 {
213 Q_UNUSED(interface)
214 Q_UNUSED(hint)
215 return QVariant();
216 }
217 QVariant
218 ImageManipulationDelegate::securityLevelIcon(const SecurityEvaluationModel::SecurityLevel level) const
219 {
220 Q_UNUSED(level)
221 return QVariant();
222 }
223 QVariant
224 ImageManipulationDelegate::historySortingCategoryIcon(const CategorizedHistoryModel::SortedProxy::Categories cat) const
225 {
226 Q_UNUSED(cat)
227 return QVariant();
228 }
229 QVariant
230 ImageManipulationDelegate::contactSortingCategoryIcon(const CategorizedContactModel::SortedProxy::Categories cat) const
231 {
232 Q_UNUSED(cat)
233 return QVariant();
234 }
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400235
Alexandre Lision7a166e42015-09-02 15:04:43 -0400236 QVariant
237 ImageManipulationDelegate::userActionIcon(const UserActionElement& state) const
238 {
239 Q_UNUSED(state)
240 return QVariant();
Alexandre Lision3b0bd332015-03-15 18:43:07 -0400241 }
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400242
Stepan Salenikovich3a6ea302016-01-08 13:54:34 -0500243 QVariant ImageManipulationDelegate::decorationRole(const QModelIndex& index)
244 {
245 Q_UNUSED(index)
246 return QVariant();
247 }
248
249 QVariant ImageManipulationDelegate::decorationRole(const Call* c)
250 {
251 Q_UNUSED(c)
252 return QVariant();
253 }
254
255 QVariant ImageManipulationDelegate::decorationRole(const ContactMethod* cm)
256 {
257 Q_UNUSED(cm)
258 return QVariant();
259 }
260
261 QVariant ImageManipulationDelegate::decorationRole(const Person* p)
262 {
263 Q_UNUSED(p)
264 return QVariant();
265 }
266
Alexandre Lision7a166e42015-09-02 15:04:43 -0400267} // namespace Interfaces