mirror of https://github.com/qTox/qTox.git
Browse Source
ported from https://github.com/sudden6/rust-identicon/blob/master/src/lib.rs but slightly changed the algorithmreviewable/pr4700/r11
3 changed files with 175 additions and 0 deletions
@ -0,0 +1,143 @@
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
Copyright © 2017 by The qTox Project Contributors |
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox. |
||||
|
||||
qTox is libre software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
qTox is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include "identicon.h" |
||||
#include "src/core/toxpk.h" |
||||
|
||||
#include <cassert> |
||||
|
||||
#include <QColor> |
||||
#include <QCryptographicHash> |
||||
#include <QDebug> |
||||
#include <QImage> |
||||
|
||||
// The following constants change the appearance of the identicon
|
||||
// they have been choosen by trying to make the output look nice.
|
||||
/**
|
||||
* @var Identicon::IDENTICON_COLOR_BYTES |
||||
* Specifies how many bytes should define the foreground color |
||||
* must be smaller than 8, else there'll be overflows |
||||
*/ |
||||
|
||||
/**
|
||||
* @var Identicon::COLORS |
||||
* Number of colors to use for the identicon |
||||
*/ |
||||
|
||||
/**
|
||||
* @var Identicon::IDENTICON_ROWS |
||||
* Specifies how many rows of blocks the identicon should have |
||||
*/ |
||||
|
||||
/**
|
||||
* @var Identicon::ACTIVE_COLS |
||||
* Width from the center to the outside, for 5 columns it's 3, 6 -> 3, 7 -> 4 |
||||
*/ |
||||
|
||||
/**
|
||||
* @var Identicon::HASH_MIN_LEN |
||||
* Min length of the hash in bytes, 7 bytes control the color, |
||||
* the rest controls the pixel placement |
||||
*/ |
||||
|
||||
/**
|
||||
* @brief Creates an Identicon, that visualizes a hash in graphical form. |
||||
* @param data Data to visualize |
||||
*/ |
||||
Identicon::Identicon(const QByteArray& data) |
||||
{ |
||||
static_assert(Identicon::COLORS == 2, "Only two colors are implemented"); |
||||
// hash with sha256
|
||||
QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Sha256); |
||||
for (int colorIndex = 0; colorIndex < COLORS; ++colorIndex) { |
||||
const QByteArray hashPart = hash.right(IDENTICON_COLOR_BYTES); |
||||
hash.truncate(hash.length() - IDENTICON_COLOR_BYTES); |
||||
|
||||
const qreal hue = bytesToColor(hashPart); |
||||
// change offset when COLORS != 2
|
||||
const qreal lig = static_cast<qreal>(colorIndex) / COLORS + 0.3; |
||||
const qreal sat = 0.5; |
||||
colors[colorIndex].setHslF(hue, sat, lig); |
||||
} |
||||
|
||||
const uint8_t* const hashBytes = reinterpret_cast<const uint8_t*>(hash.constData()); |
||||
// compute the block colors from the hash
|
||||
for (int row = 0; row < IDENTICON_ROWS; ++row) { |
||||
for (int col = 0; col < ACTIVE_COLS; ++col) { |
||||
const int hashIdx = row * ACTIVE_COLS + col; |
||||
const uint8_t colorIndex = hashBytes[hashIdx] % COLORS; |
||||
identiconColors[row][col] = colorIndex; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* @brief Converts a series of IDENTICON_COLOR_BYTES bytes to a value in the range 0.0..1.0 |
||||
* @param bytes Bytes to convert to a color |
||||
* @return Value in the range of 0.0..1.0 |
||||
*/ |
||||
float Identicon::bytesToColor(QByteArray bytes) |
||||
{ |
||||
static_assert(IDENTICON_COLOR_BYTES <= 8, "IDENTICON_COLOR max value is 8"); |
||||
const uint8_t* const bytesChr = reinterpret_cast<const uint8_t*>(bytes.constData()); |
||||
assert(bytes.length() == IDENTICON_COLOR_BYTES); |
||||
|
||||
// get foreground color
|
||||
uint64_t hue = bytesChr[0]; |
||||
|
||||
// convert the last bytes to an uint
|
||||
for (int i = 1; i < IDENTICON_COLOR_BYTES; ++i) { |
||||
hue = hue << 8; |
||||
hue += bytesChr[i]; |
||||
} |
||||
|
||||
// normalize to 0.0 ... 1.0
|
||||
return (static_cast<float>(hue)) |
||||
/ (((static_cast<uint64_t>(1)) << (8 * IDENTICON_COLOR_BYTES)) - 1); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Writes the Identicon to a QImage |
||||
* @param scaleFactor the image will be a square with scaleFactor * IDENTICON_ROWS pixels, |
||||
* must be >= 1 |
||||
* @return a QImage with the identicon |
||||
*/ |
||||
QImage Identicon::toImage(int scaleFactor) |
||||
{ |
||||
if (scaleFactor < 1) { |
||||
qDebug() << "Can't scale with values <1, clamping to 1"; |
||||
scaleFactor = 1; |
||||
} |
||||
|
||||
scaleFactor *= IDENTICON_ROWS; |
||||
|
||||
QImage pixels(IDENTICON_ROWS, IDENTICON_ROWS, QImage::Format_RGB888); |
||||
|
||||
for (int row = 0; row < IDENTICON_ROWS; ++row) { |
||||
for (int col = 0; col < IDENTICON_ROWS; ++col) { |
||||
// mirror on vertical axis
|
||||
const int columnIdx = abs((col * 2 - (IDENTICON_ROWS - 1)) / 2); |
||||
const int colorIdx = identiconColors[row][columnIdx]; |
||||
pixels.setPixel(col, row, colors[colorIdx].rgb()); |
||||
} |
||||
} |
||||
|
||||
// scale up without smoothing to make it look sharp
|
||||
return pixels.scaled(scaleFactor, scaleFactor, Qt::IgnoreAspectRatio, Qt::FastTransformation); |
||||
} |
@ -0,0 +1,30 @@
@@ -0,0 +1,30 @@
|
||||
#ifndef IDENTICON_H |
||||
#define IDENTICON_H |
||||
|
||||
#include <QColor> |
||||
#include <QImage> |
||||
|
||||
class Identicon |
||||
{ |
||||
public: |
||||
Identicon(const QByteArray& data); |
||||
QImage toImage(int scaleFactor = 1); |
||||
|
||||
public: |
||||
static constexpr int IDENTICON_ROWS = 5; |
||||
|
||||
private: |
||||
float bytesToColor(QByteArray bytes); |
||||
|
||||
private: |
||||
static constexpr int COLORS = 2; |
||||
static constexpr int ACTIVE_COLS = (IDENTICON_ROWS + 1) / 2; |
||||
static constexpr int IDENTICON_COLOR_BYTES = 6; |
||||
static constexpr int HASH_MIN_LEN = ACTIVE_COLS * IDENTICON_ROWS |
||||
+ COLORS * IDENTICON_COLOR_BYTES; |
||||
|
||||
uint8_t identiconColors[IDENTICON_ROWS][ACTIVE_COLS]; |
||||
QColor colors[COLORS]; |
||||
}; |
||||
|
||||
#endif // IDENTICON_H
|
Loading…
Reference in new issue