1 /*
2 Drawpile - a collaborative drawing program.
3
4 Copyright (C) 2018 Calle Laakkonen
5
6 Drawpile is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Drawpile is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Drawpile. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "identicon.h"
21
22 #include <QPainter>
23 #include <QCryptographicHash>
24 #include <QtEndian>
25 #include <QtMath>
26
27 namespace {
28 class HashRand {
29 public:
HashRand(const QByteArray & seed)30 HashRand(const QByteArray &seed)
31 : m_pos(0)
32 {
33 m_seed = QCryptographicHash::hash(seed, QCryptographicHash::Sha256);
34 }
35
operator ()(unsigned int bound)36 unsigned int operator()(unsigned int bound)
37 {
38 if(m_pos+4 > m_seed.length()) {
39 m_pos = 0;
40 m_seed = QCryptographicHash::hash(m_seed, QCryptographicHash::Sha256);
41 } else {
42 m_pos += 4;
43 }
44
45 return qFromBigEndian<quint32>(m_seed.constData()+m_pos) % bound;
46 }
47
48 private:
49 QByteArray m_seed;
50 int m_pos;
51 };
52 }
53
make_identicon(const QString & name,const QSize & size)54 QImage make_identicon(const QString &name, const QSize &size)
55 {
56 HashRand rand {name.toUtf8()};
57
58 QImage image(size, QImage::Format_ARGB32_Premultiplied);
59 image.fill(QColor::fromHsl(rand(360), 255, 120));
60
61 // Draw the decorative elements
62 QPainter painter(&image);
63 painter.setRenderHint(QPainter::Antialiasing);
64 painter.setPen(Qt::NoPen);
65 const double offset = rand(180) / M_PI;
66 for(int i=0;i<3;++i) {
67 const QPointF c { size.width() / 2.0, size.height() / 2.0 };
68 const double r = size.width() * 2;
69 painter.setBrush(QColor::fromHsl(rand(360), 255, 180, 255/2));
70 painter.drawEllipse(QRectF(
71 c.x() + sin(offset + i/3.0 * M_PI*2) * r - r,
72 c.y() + cos(offset + i/3.0 * M_PI*2) * r - r,
73 r*2,
74 r*2
75 ));
76 }
77
78 // Draw the name's first letter
79 QFont font;
80 font.setPixelSize(size.height() * 0.7);
81 painter.setFont(font);
82 painter.setPen(Qt::white);
83 painter.drawText(QRect(QPoint(), size), Qt::AlignCenter, name.left(1));
84
85 // Draw the circular mask
86 QImage mask(size, QImage::Format_ARGB32_Premultiplied);
87 mask.fill(0);
88 QPainter maskPainter(&mask);
89 maskPainter.setRenderHint(QPainter::Antialiasing);
90 maskPainter.setBrush(Qt::white);
91 maskPainter.drawEllipse(1, 1, size.width()-2, size.height()-2);
92
93 painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
94 painter.drawImage(0, 0, mask);
95
96 return image;
97 }
98
99