= identiconpp
:toc: preamble

:project: identiconpp
:uri-base: https://schlomp.space/tastytea/{project}
:uri-branch-master: {uri-base}/src/branch/master
:uri-reference-base: https://doc.schlomp.space/{project}
:uri-images-base: {uri-reference-base}
:uri-sigil: https://github.com/cupcake/sigil/
:uri-pydenticon: https://github.com/azaghal/pydenticon/
:uri-overlay: https://schlomp.space/tastytea/overlay
:uri-pgpkey: https://tastytea.de/tastytea_autosign.asc
:uri-gcc: https://gcc.gnu.org/
:uri-clang: https://clang.llvm.org/
:uri-cmake: https://cmake.org/
:uri-imagemagick: https://www.imagemagick.org/
:uri-asciidoc: http://asciidoc.org/
:uri-catch: https://github.com/catchorg/Catch2

*identiconpp* is a library to generate identicons for C++.

You get the images as `Magick::Image`. This allows you to make all kinds of
modifications.

.Used algorithms, left to right: 4x4 ltr_symmetric, 20px padding; 5x5 sigil; 5x5 ltr_asymmetric; 6x4 ltr_symmetric, 10px padding
====
image:{uri-images-base}/identicon1.png[]
image:{uri-images-base}/identicon2.png[]
image:{uri-images-base}/identicon3.png[]
image:{uri-images-base}/identicon4.png[]

The example images above are generated using
link:{uri-branch-master}/examples/example.cpp[example.cpp].
====

== Features

* [x] Symmetric identicons
* [x] sigil identicons
* [x] Asymmetric identicons
* [x] Padding

== Usage

The HTML reference can be generated with `build_doc.sh`, if doxygen is
installed. It is also available at
link:{uri-reference-base}/classIdenticonpp.html[doc.schlomp.space/identiconpp/].

You need to generate hashes yourself, any hexadecimal string will do. Make sure
to use a safe hashing algorithm for sensitive data (*not MD5*). You can select
as many columns and rows as you like, but make sure you have enough entropy.
If something seems to be wrong, exceptions will be thrown.

The "sigil" algorithm generates the same results as link:{uri-sigil}[sigil] and
link:{uri-pydenticon}[pydenticon].

=== Example

[source,c++]
----
// Compile with g++ $(pkg-config --libs --cflags identiconpp)
#include <iostream>
#include <identiconpp.hpp>
#include <Magick++/Image.h>

int main()
{
    Identiconpp identicon(5, 5, Identiconpp::algorithm::ltr_symmetric,
                          "ffffff80", { "800000ff" }, { 10, 10 });
    Magick::Image img;
    img = identicon.generate("55502f40dc8b7c769880b10874abc9d0", 200);
    img.write("identicon.png");

    std::cout << identicon.generate_base64("png", "5550", 200) << std::endl;
}
----

== Install

=== Gentoo

Gentoo ebuilds are available via my link:{uri-overlay}[repository].

=== Automatically generated packages

Binary packages are generated automatically for each
link:{uri-base}/releases[release] for Debian stretch and CentOS 7. They are
signed with my link:{uri-pgpkey}[automatic signing key].

=== From source

==== Dependencies

* C++ compiler (tested: link:{uri-gcc}[gcc] 6/8/9, link:{uri-clang}[clang] 7)
* {uri-cmake}[cmake] (at least 3.6)
* link:{uri-imagemagick}[imagemagick] (tested: 7.0 / 6.7)
* Optional:
** Manpage: {uri-asciidoc}[asciidoc] (tested: 8.6)
** Tests: {uri-catch}[catch] (tested: 2.5 / 1.2)

On a Debian system, install the packages:
`build-essential cmake libmagick++-dev`.

==== Compile

[source,shell]
----
mkdir build
cd build
cmake ..
cmake --build .
make install
----

.cmake options:
* `-DCMAKE_BUILD_TYPE=Debug` for a debug build
* `-DWITH_TESTS=YES` to build tests
* One of:
** `-DWITH_DEB=YES` to generate a deb-package
** `-DWITH_RPM=YES` to generate an rpm-package

To generate a binary package, run `make package`.

include::{uri-base}/raw/branch/master/CONTRIBUTING.adoc[]

== Algorithms

=== ltr_symmetric

* Create image with width=columns, height=rows.
* Set background color.
* Select half of the columns, or half of the columns + 1 if uneven.
** `columns / 2 + columns % 2`
* Pixels are drawn from left to right, top to bottom.
* Use bits from digest to determine if a pixel is painted(1) or not(0).
* Mirror the pixels vertically.
* Use the following bits to pick the foreground color.
** You need `floor(log2(n_colors)) + 1` bits.
* Scale image proportionally to requested width.

----
 0111 0011 1101 1100 […] 1111 0111 0101 0111
^                            ^
+----------------------------+-------------->
             |                      |
        pixel matrix        foreground color
----

Implemented in
link:{uri-branch-master}/src/ltr_symmetric.cpp[ltr_symmetric.cpp].

=== ltr_asymmetric

* Create image with width=columns, height=rows.
* Set background color.
* Pixels are drawn from left to right, top to bottom.
* Use bits from digest to determine if a pixel is painted(1) or not(0).
* Use the following bits to pick the foreground color.
** You need `floor(log2(n_colors)) + 1` bits.
* Scale image proportionally to requested width.

----
 0111 0011 1101 1100 […] 1111 0111 0101 0111
^                            ^
+----------------------------+-------------->
             |                      |
        pixel matrix        foreground color
----

Implemented in
link:{uri-branch-master}/src/ltr_asymmetric.cpp[ltr_asymmetric.cpp].

=== sigil

* Create image with width=columns, height=rows.
* Set background color.
* Select half of the columns, or half of the columns + 1 if uneven.
** `columns / 2 + columns % 2`
* Pixels are drawn from top to bottom, left to right.
* Use the first 8 bits to pick the foreground color.
* Use the following bits to determine if a pixel is painted(1) or not(0).
* Mirror the pixels vertically.
* Scale image proportionally to requested width.

----
 0111 0011 1101 1100
^         ^
+---------+--------->
     |            |
foreground color  |
             pixel matrix
----

Implemented in link:{uri-branch-master}/src/sigil.cpp[sigil.cpp].
