Compare commits

..

No commits in common. "master" and "0.6.1" have entirely different histories.

22 changed files with 668 additions and 460 deletions

View File

@ -60,18 +60,21 @@ steps:
- name: debian-package-cache
path: /var/cache/apt/archives
- name: clang7
image: debian:buster-slim
- name: clang6
image: debian:stretch-slim
pull: always
environment:
CXX: clang++
CXX: clang++-6.0
CXXFLAGS: -pipe -O2
LANG: en_US.utf-8
commands:
- rm /etc/apt/apt.conf.d/docker-clean
- alias apt-get='rm -f /var/cache/apt/archives/lock && apt-get'
- echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release
- echo "deb http://deb.debian.org/debian stretch-backports main" >> /etc/apt/sources.list.d/stretch.list
- apt-get update -q
- apt-get install -qy clang cmake pkg-config libmagick++-dev
- apt-get install -qy -t stretch-backports clang-6.0
- apt-get install -qy cmake pkg-config libmagick++-dev
- rm -rf build && mkdir -p build && cd build
- cmake ..
- cmake --build .
@ -99,7 +102,7 @@ trigger:
- tag
steps:
- name: Debian stretch
- name: deb
image: debian:stretch-slim
pull: always
environment:
@ -110,74 +113,49 @@ steps:
- rm /etc/apt/apt.conf.d/docker-clean
- alias apt-get='rm -f /var/cache/apt/archives/lock && apt-get'
- apt-get update -q
- apt-get install -qy g++-6 cmake pkg-config libmagick++-dev gnupg dpkg-dev d-shlibs lsb-release
- apt-get install -qy g++-6 cmake pkg-config libmagick++-dev gnupg
- rm -rf build && mkdir -p build && cd build
- cmake -DWITH_DEB=YES ..
- make package
- gpg --import /var/autosign_gpg.key
- gpg --verbose --detach-sign *.deb
- cp -v identiconpp_${DRONE_TAG}-0_amd64_stretch.deb ..
- cp -v identiconpp_${DRONE_TAG}-0_amd64_stretch.deb.sig ..
- cp -v identiconpp_${DRONE_TAG}-0_amd64.deb ..
- cp -v identiconpp_${DRONE_TAG}-0_amd64.deb.sig ..
volumes:
- name: debian-package-cache
path: /var/cache/apt/archives
- name: gpg-key
path: /var/autosign_gpg.key
- name: Debian buster
image: debian:buster-slim
- name: rpm
image: centos:7
pull: always
environment:
CXX: g++-8
CXX: /opt/rh/devtoolset-6/root/usr/bin/g++
CXXFLAGS: -pipe -O2
LANG: en_US.utf-8
commands:
- rm /etc/apt/apt.conf.d/docker-clean
- alias apt-get='rm -f /var/cache/apt/archives/lock && apt-get'
- apt-get update -q
- apt-get install -qy build-essential cmake pkg-config libmagick++-dev gnupg dpkg-dev d-shlibs lsb-release
- sed -i 's/keepcache=0/keepcache=1/' /etc/yum.conf
- curl -s -o /var/cache/yum/epel-release-latest-7.noarch.rpm http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
- rpm -i /var/cache/yum/epel-release-latest-7.noarch.rpm
- yum install -qy centos-release-scl
- yum install -qy devtoolset-6
- scl enable devtoolset-6 bash
- yum install -qy rpm-build ImageMagick-c++-devel gnupg
- yum --enablerepo=epel install -qy cmake3
- rm -rf build && mkdir -p build && cd build
- cmake -DWITH_DEB=YES ..
- cmake3 -DWITH_RPM=YES ..
- make package
- gpg --import /var/autosign_gpg.key
- gpg --verbose --detach-sign *.deb
- cp -v identiconpp_${DRONE_TAG}-0_amd64_buster.deb ..
- cp -v identiconpp_${DRONE_TAG}-0_amd64_buster.deb.sig ..
- gpg --verbose --detach-sign *.rpm
- cp -v identiconpp-${DRONE_TAG}-0.x86_64.rpm ..
- cp -v identiconpp-${DRONE_TAG}-0.x86_64.rpm.sig ..
volumes:
- name: debian-package-cache
path: /var/cache/apt/archives
- name: centos-package-cache
path: /var/cache/yum
- name: gpg-key
path: /var/autosign_gpg.key
# - name: CentOS 7
# image: centos:7
# pull: always
# environment:
# CXX: /opt/rh/devtoolset-6/root/usr/bin/g++
# CXXFLAGS: -pipe -O2
# LANG: en_US.utf-8
# commands:
# - sed -i 's/keepcache=0/keepcache=1/' /etc/yum.conf
# - curl -s -o /var/cache/yum/epel-release-latest-7.noarch.rpm http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
# - rpm -i /var/cache/yum/epel-release-latest-7.noarch.rpm
# - yum install -qy centos-release-scl
# - yum install -qy devtoolset-6
# - scl enable devtoolset-6 bash
# - yum install -qy rpm-build ImageMagick-c++-devel gnupg redhat-lsb-core
# - yum --enablerepo=epel install -qy cmake3
# - rm -rf build && mkdir -p build && cd build
# - cmake3 -DWITH_RPM=YES ..
# - make package
# - gpg --import /var/autosign_gpg.key
# - gpg --verbose --detach-sign *.rpm
# - cp -v identiconpp-${DRONE_TAG}-0.x86_64.centos7.rpm ..
# - cp -v identiconpp-${DRONE_TAG}-0.x86_64.centos7.rpm.sig ..
# volumes:
# - name: centos-package-cache
# path: /var/cache/yum
# - name: gpg-key
# path: /var/autosign_gpg.key
- name: release
image: plugins/gitea-release
pull: always
@ -188,12 +166,10 @@ steps:
title: ${DRONE_TAG}
prerelease: true
files:
- identiconpp_${DRONE_TAG}-0_amd64_stretch.deb
- identiconpp_${DRONE_TAG}-0_amd64_stretch.deb.sig
- identiconpp_${DRONE_TAG}-0_amd64_buster.deb
- identiconpp_${DRONE_TAG}-0_amd64_buster.deb.sig
# - identiconpp-${DRONE_TAG}-0.x86_64.centos7.rpm
# - identiconpp-${DRONE_TAG}-0.x86_64.centos7.rpm.sig
- identiconpp_${DRONE_TAG}-0_amd64.deb
- identiconpp_${DRONE_TAG}-0_amd64.deb.sig
- identiconpp-${DRONE_TAG}-0.x86_64.rpm
- identiconpp-${DRONE_TAG}-0.x86_64.rpm.sig
checksum:
- sha512

View File

@ -1,20 +0,0 @@
# Configuration file for EditorConfig.
# More information is available under <https://editorconfig.org/>.
root = true
[*]
indent_style = space
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 80
[*.?pp]
indent_size = 4
tab_width = 4
[{CMakeLists.txt,*.cmake}]
indent_size = 2
tab_width = 2

View File

@ -1,54 +1,40 @@
# Support version 3.6 and above, but use policy settings up to 3.14.
# 3.6 is needed because of IMPORTED_TARGET in pkg_check_modules().
cmake_minimum_required(VERSION 3.6...3.14)
# Ranges are supported from 3.12, set policy to current for < 3.12.
if(${CMAKE_VERSION} VERSION_LESS 3.12)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
endif()
cmake_minimum_required (VERSION 3.2)
project(identiconpp
VERSION 0.7.3
VERSION 0.6.1
LANGUAGES CXX)
# DESCRIPTION was introduced in version 3.9.
if(NOT (${CMAKE_VERSION} VERSION_LESS 3.9))
set(PROJECT_DESCRIPTION
"Library to generate identicons for C++.")
endif()
option(WITH_TESTS "Enable Tests" NO)
option(BUILD_SHARED_LIBS "Build shared libraries." YES)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(DEBUG_CXXFLAGS
"-Wall"
"-Wextra"
"-Wpedantic"
"-ftrapv"
"-fsanitize=undefined"
"-g"
"-Og"
"-fno-omit-frame-pointer")
set(DEBUG_LDFLAGS
"-fsanitize=undefined")
add_compile_options("$<$<CONFIG:Debug>:${DEBUG_CXXFLAGS}>")
# add_link_options was introduced in version 3.13.
if(${CMAKE_VERSION} VERSION_LESS 3.13)
set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${DEBUG_LDFLAGS}")
else()
add_link_options("$<$<CONFIG:Debug>:${DEBUG_LDFLAGS}>")
endif()
set(CMAKE_CXX_FLAGS_DEBUG
"${CMAKE_CXX_FLAGS_DEBUG} -Wall -Wextra -Wpedantic -ftrapv \
-fsanitize=undefined -g -Og -fno-omit-frame-pointer")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-DDEBUG=1)
endif()
include(GNUInstallDirs)
include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(${PROJECT_BINARY_DIR})
install(FILES README.md DESTINATION ${CMAKE_INSTALL_DOCDIR})
add_subdirectory(src)
add_subdirectory(include)
add_subdirectory(cmake)
add_subdirectory(pkg-config)
configure_file("${PROJECT_SOURCE_DIR}/${PROJECT_NAME}.pc.in"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" @ONLY)
configure_file("${PROJECT_SOURCE_DIR}/${PROJECT_NAME}_c.pc.in"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_c.pc" @ONLY)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_c.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
if(WITH_TESTS)
add_subdirectory(tests)

View File

@ -1,49 +0,0 @@
:contact-coc: tastytea@tastytea.de
== Code of Conduct
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, education, ethnicity, gender identity and expression, level of
experience, nationality, personal appearance, race, religion, sex
characteristics, sexual identity and orientation or socio-economic status.
=== Examples
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language.
* Being respectful of differing viewpoints and experiences.
* Gracefully accepting constructive criticism.
* Focusing on what is best for the community.
* Showing empathy towards other community members.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances.
* Trolling, insulting/derogatory comments, and personal attacks.
* Public or private harassment.
* Publishing others private information, such as a physical or electronic
address, without explicit permission.
=== Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at {contact-coc}.
All complaints will be reviewed and investigated and will result in a response
that is deemed necessary and appropriate to the circumstances. The project team
is obligated to maintain confidentiality with regard to the reporter of an
incident.
=== Attribution
This Code of Conduct is adapted from the Contributor Covenant, version 1.4,
available at
https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

View File

@ -1,29 +0,0 @@
:project: identiconpp
:uri-base: https://schlomp.space/tastytea/{project}
:uri-coc: {uri-base}/src/branch/master/CODE_OF_CONDUCT.adoc
:contact-email: tastytea@tastytea.de
:contact-xmpp: {contact-email}
:contact-fediverse: https://likeable.space/users/tastytea
== How to contribute
Read the link:{uri-coc}[Code of Conduct].
=== Reporting bugs or suggesting enhancements
Before reporting a bug, please
https://schlomp.space/tastytea/{project}/issues[perform a search] to see if the
problem has already been reported. If it has, add a comment to the existing
issue instead of opening a new one. Same for enhancements.
You can also contact me via mailto:{contact-email}[E-Mail],
link:xmpp:{contact-xmpp}[XMPP] or the {contact-fediverse}[Fediverse] if you
don't want to open an account.
=== Pull requests
Please use similar coding conventions as the rest of the project. The basic rule
to remember is to write code in the same style as the existing/surrounding code.
You can also send me your patches via mailto:{contact-email}[E-Mail], ideally
using `git format-patch` or `git send-email`.

View File

@ -1,194 +0,0 @@
= 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]. 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].

206
README.md Normal file
View File

@ -0,0 +1,206 @@
**identiconpp** is a library to generate identicons for C++ and C.
You get the images as `Magick::Image`. This allows you to make all kinds of
modifications.
![](https://doc.schlomp.space/identiconpp/identicon1.png
"4x4 identicon, ltr_symmetric, 20px padding")
![](https://doc.schlomp.space/identiconpp/identicon2.png
"5x5 identicon, sigil")
![](https://doc.schlomp.space/identiconpp/identicon3.png
"5x5 identicon, ltr_asymmetric")
![](https://doc.schlomp.space/identiconpp/identicon4.png
"6x4 identicon, ltr_symmetric, 10px padding")
The example images above are generated using [example.cpp]
(https://schlomp.space/tastytea/identiconpp/src/branch/master/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 [doc.schlomp.space/identiconpp/]
(https://doc.schlomp.space/identiconpp/classIdenticonpp.html).
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
[sigil](https://github.com/cupcake/sigil/) and
[pydenticon](https://github.com/azaghal/pydenticon/).
### Example
``` 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;
}
```
### C interface
This is somewhat experimental. Have a look at [example.c]
(https://schlomp.space/tastytea/identiconpp/src/branch/master/example.c) and
[identiconpp_c.h](https://doc.schlomp.space/identiconpp/identiconpp__c_8h.html).
It seems to be impossible to use `Magick++` and `MagickWand` in the same
library, so the images are returned as base64-encoded strings.
## Install
### Gentoo
Gentoo ebuilds are available via my
[repository](https://schlomp.space/tastytea/overlay).
### Automatically generated packages
Binary packages are generated automatically for each
[release](https://schlomp.space/tastytea/identiconpp/releases) in the formats
`deb` and `rpm`. They are signed with my [automatic signing
key](https://tastytea.de/tastytea_autosign.asc).
### From source
#### Dependencies
* C++ compiler (tested: [gcc](https://gcc.gnu.org/) 6/8/9,
[clang](https://llvm.org/) 6)
* [cmake](https://cmake.org/) (at least 3.2)
* [imagemagick](https://www.imagemagick.org/) (tested: 7.0 / 6.7)
* Optional:
* Tests: [Catch](https://github.com/catchorg/Catch2) (tested: 2.3 / 1.2)
On a Debian system, install the packages:
`build-essential cmake libmagick++-dev`.
#### Compile
``` shell
mkdir build
cd build
cmake ..
make
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, execute `make package`
## Contributing
Contributions are always welcome. You can submit them as pull requests on
schlomp.space or via email to `tastytea`@`tastytea.de` (ideally using
`git format-patch` or `git send-email`). Please do not submit them via GitHub,
it is just a mirror.
## Contact
See https://tastytea.de/
## License & Copyright
``` text
Copyright © 2018 tastytea <tastytea@tastytea.de>.
License GPLv3: GNU GPL version 3 <https://www.gnu.org/licenses/gpl-3.0.html>.
This program comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
```
## 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.
```PLAIN
0111 0011 1101 1100 […] 1111 0111 0101 0111
^ ^
+----------------------------+-------------->
| |
pixel matrix foreground color
```
Implemented in [ltr_symmetric.cpp]
(https://schlomp.space/tastytea/identiconpp/src/branch/master/src/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.
```PLAIN
0111 0011 1101 1100 […] 1111 0111 0101 0111
^ ^
+----------------------------+-------------->
| |
pixel matrix foreground color
```
Implemented in [ltr_asymmetric.cpp]
(https://schlomp.space/tastytea/identiconpp/src/branch/master/src/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.
```PLAIN
0111 0011 1101 1100
^ ^
+---------+--------->
| |
foreground color |
pixel matrix
```
Implemented in [sigil.cpp]
(https://schlomp.space/tastytea/identiconpp/src/branch/master/src/sigil.cpp)

View File

@ -1,19 +0,0 @@
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
write_basic_package_version_file("${PROJECT_NAME}ConfigVersion.cmake"
VERSION ${PACKAGE_VERSION}
COMPATIBILITY ExactVersion) # NOTE: Set to SameMajorVersion when stable.
install(EXPORT ${PROJECT_NAME}Targets
FILE "${PROJECT_NAME}Targets.cmake"
NAMESPACE "${PROJECT_NAME}::"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
configure_file("${PROJECT_NAME}Config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" @ONLY)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")

View File

@ -1,7 +0,0 @@
include(CMakeFindDependencyMacro)
include(GNUInstallDirs)
find_dependency(PkgConfig REQUIRED)
pkg_check_modules(Magick++ REQUIRED IMPORTED_TARGET Magick++)
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")

104
example.c Normal file
View File

@ -0,0 +1,104 @@
/* This file is part of identiconpp.
* Public Domain / CC-0
*
* Compile with gcc --std=c99 \
* $(pkg-config --cflags --libs identiconpp_c.pc MagickWand openssl)
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "identiconpp_c.h"
#include <MagickWand/MagickWand.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
char *b64decode(char *input, int length)
{
BIO *b64, *bmem;
char *buffer = (char *)malloc(length);
memset(buffer, 0, length);
b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
bmem = BIO_new_mem_buf(input, length);
bmem = BIO_push(b64, bmem);
BIO_read(bmem, buffer, length);
BIO_free_all(bmem);
return buffer;
}
int main(int argc, char *argv[])
{
char digest[65] = "973dfe463ec85785f5f95af5ba3906ee"
"db2d931c24e69824a89ea65dba4e813b";
const char colors[6][9] =
{
"800000ff",
"008000ff",
"000080ff",
"808000ff",
"008080ff",
"800080ff"
};
if (argc > 1)
{
strncpy(digest, argv[1], 64);
}
MagickWand *mw = NULL;
MagickWandGenesis();
mw = NewMagickWand();
{
const uint8_t padding[2] = { 20, 20 };
identiconpp_setup(4, 4, identiconpp_ltr_symmetric,
"ffffffff", colors, 6, padding);
uint64_t len = identiconpp_generate("png", digest, 200);
char base64[len];
strcpy(base64, identiconpp_base64());
MagickReadImageBlob(mw, b64decode(base64, len), len);
MagickWriteImage(mw, "identicon1.png");
}
{
const uint8_t padding[2] = { 0, 0 };
identiconpp_setup(5, 5, identiconpp_sigil,
"00000080", colors, 6, padding);
uint64_t len = identiconpp_generate("png", digest, 200);
char base64[len];
strcpy(base64, identiconpp_base64());
MagickReadImageBlob(mw, b64decode(base64, len), len);
MagickWriteImage(mw, "identicon2.png");
}
{
const uint8_t padding[2] = { 0, 0 };
identiconpp_setup(5, 5, identiconpp_ltr_asymmetric,
"000000ff", colors, 6, padding);
uint64_t len = identiconpp_generate("png", digest, 200);
char base64[len];
strcpy(base64, identiconpp_base64());
MagickReadImageBlob(mw, b64decode(base64, len), len);
MagickWriteImage(mw, "identicon3.png");
}
{
const uint8_t padding[2] = { 10, 10 };
identiconpp_setup(6, 4, identiconpp_ltr_symmetric,
"000000c0", colors, 6, padding);
uint64_t len = identiconpp_generate("png", digest, 200);
char base64[len];
strcpy(base64, identiconpp_base64());
MagickReadImageBlob(mw, b64decode(base64, len), len);
MagickWriteImage(mw, "identicon4.png");
}
DestroyMagickWand(mw);
MagickWandTerminus();
}

View File

@ -1,4 +0,0 @@
# You need to install identiconpp first so that CMake can find it.
find_package(identiconpp REQUIRED CONFIG)
add_executable(example example.cpp)
target_link_libraries(example PRIVATE identiconpp::identiconpp)

View File

@ -5,7 +5,7 @@ libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
Name: ${name}
Description: @PROJECT_DESCRIPTION@
Description: Library to generate identicons for C++ and C.
Version: @PROJECT_VERSION@
Libs: -L${libdir} -l${name}
Cflags: -I${includedir}

11
identiconpp_c.pc.in Normal file
View File

@ -0,0 +1,11 @@
name=@PROJECT_NAME@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
Name: ${name}
Description: Library to generate identicons for C++ and C.
Version: @PROJECT_VERSION@
Libs: -L${libdir} -l${name}
Cflags: -I${includedir}

View File

@ -1,4 +0,0 @@
include(GNUInstallDirs)
install(FILES "identiconpp.hpp"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")

View File

@ -8,7 +8,7 @@ set(CPACK_PACKAGE_DESCRIPTION_SUMMARY
"Library to generate identicons for C++ and C.")
set(CPACK_PACKAGE_CONTACT "tastytea <tastytea@tastytea.de>")
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
set(CPACK_RESOURCE_FILE_README "${PROJECT_SOURCE_DIR}/README.adoc")
set(CPACK_RESOURCE_FILE_README "${PROJECT_SOURCE_DIR}/README.md")
list(APPEND CPACK_SOURCE_IGNORE_FILES "/\\\\.git"
"/.gitignore"
"/build/"
@ -31,11 +31,8 @@ if (WITH_DEB)
execute_process(COMMAND dpkg --print-architecture
OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND lsb_release --codename --short
OUTPUT_VARIABLE DEBIAN_CODENAME
OUTPUT_STRIP_TRAILING_WHITESPACE)
set(CPACK_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}_${DEBIAN_CODENAME}")
"${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
endif()
if (WITH_RPM)
@ -43,19 +40,9 @@ if (WITH_RPM)
set(CPACK_RPM_PACKAGE_LICENSE "GPL-3")
set(CPACK_RPM_PACKAGE_URL
"https://schlomp.space/tastytea/${CMAKE_PROJECT_NAME}")
set(CPACK_RPM_PACKAGE_REQUIRES "libMagick++")
set(CPACK_RPM_PACKAGE_REQUIRES "libMagick++, libxdg-basedir >= 1.2.0")
set(CPACK_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.${CPACK_PACKAGE_ARCHITECTURE}")
execute_process(COMMAND lsb_release --id --short
OUTPUT_VARIABLE OS
OUTPUT_STRIP_TRAILING_WHITESPACE)
if("${OS}" STREQUAL "CentOS")
execute_process(COMMAND rpm -E %{rhel}
OUTPUT_VARIABLE OS_RELEASE
OUTPUT_STRIP_TRAILING_WHITESPACE)
set(CPACK_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_FILE_NAME}.centos${OS_RELEASE}")
endif()
endif()
include(CPack)

View File

@ -1,7 +0,0 @@
include(GNUInstallDirs)
configure_file("${PROJECT_NAME}.pc.in"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")

View File

@ -1,25 +1,18 @@
include(GNUInstallDirs)
find_package(PkgConfig REQUIRED)
pkg_check_modules(Magick++ REQUIRED IMPORTED_TARGET Magick++)
pkg_check_modules(MAGICPP REQUIRED Magick++)
include_directories(${MAGICPP_INCLUDE_DIRS})
link_directories(${MAGICPP_LIBRARY_DIRS})
file(GLOB sources *.cpp)
add_library(${PROJECT_NAME}
${sources} ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}.hpp)
add_library(${PROJECT_NAME} SHARED ${sources})
target_link_libraries(${PROJECT_NAME} ${MAGICPP_LIBRARIES})
target_compile_options(${PROJECT_NAME} PUBLIC ${MAGICPP_CFLAGS})
set_target_properties(${PROJECT_NAME} PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${${PROJECT_NAME}_VERSION_MAJOR})
target_include_directories(${PROJECT_NAME}
PUBLIC
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
target_link_libraries(${PROJECT_NAME} PUBLIC PkgConfig::Magick++)
install(TARGETS ${PROJECT_NAME}
EXPORT "${PROJECT_NAME}Targets"
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES ${CMAKE_PROJECT_NAME}.hpp ${CMAKE_PROJECT_NAME}_c.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

103
src/c_interface.cpp Normal file
View File

@ -0,0 +1,103 @@
/* This file is part of identiconpp.
* Copyright © 2019 tastytea <tastytea@tastytea.de>
*
* This program is free 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, version 3.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <vector>
#include <memory>
#include <exception>
#include <iostream>
#include <Magick++/Image.h>
#include <Magick++/Blob.h>
#include "identiconpp.hpp"
#include "debug.hpp"
#include "identiconpp_c.h"
using std::cerr;
using std::endl;
static std::unique_ptr<Identiconpp> identicon;
static string base64;
bool identiconpp_setup(const uint8_t columns, const uint8_t rows,
identiconpp_algorithm type,
const char background[9],
const char foreground[][9],
const uint8_t foreground_len,
const uint8_t padding[2])
{
Identiconpp::algorithm algo = Identiconpp::algorithm::ltr_symmetric;
switch (type)
{
case identiconpp_ltr_symmetric:
{
algo = Identiconpp::algorithm::ltr_symmetric;
break;
}
case identiconpp_ltr_asymmetric:
{
algo = Identiconpp::algorithm::ltr_asymmetric;
break;
}
case identiconpp_sigil:
{
algo = Identiconpp::algorithm::sigil;
break;
}
}
std::vector<string> vforeground;
for (uint8_t i = 0; i < foreground_len; ++i)
{
vforeground.push_back(foreground[i]);
}
try
{
identicon = std::make_unique<Identiconpp>(
Identiconpp(columns, rows, algo, background, vforeground,
{ padding[0], padding[1] }));
}
catch (const std::exception &e)
{
cerr << e.what() << endl;
return false;
}
return true;
}
uint64_t identiconpp_generate(const char magick[],
const char digest[], const uint16_t width)
{
try
{
Magick::Image img = identicon->generate(digest, width);
Magick::Blob blob;
img.magick(magick);
img.write(&blob);
base64 = blob.base64();
return blob.base64().length();
}
catch (const std::exception &e)
{
cerr << e.what() << endl;
return 0;
}
}
const char *identiconpp_base64()
{
return base64.c_str();
}

99
src/identiconpp_c.h Normal file
View File

@ -0,0 +1,99 @@
/* This file is part of identiconpp.
* Copyright © 2019 tastytea <tastytea@tastytea.de>
*
* This program is free 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, version 3.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef IDENTICONPP_C_H
#define IDENTICONPP_C_H
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
/*!
* @brief C interface for identiconpp.
* @file identiconpp_c.h
* @example example.c
*/
/*!
* @brief List of identicon algorithms
*/
typedef enum
{
//! Generates symmetric (vertically mirrored) identicons.
identiconpp_ltr_symmetric,
//! Generates asymmetric identicons.
identiconpp_ltr_asymmetric,
/*!
* Generates the same results as
* [sigil](https://github.com/cupcake/sigil/) and
* [pydenticon](https://github.com/azaghal/pydenticon/).
*/
identiconpp_sigil
} identiconpp_algorithm;
/*!
* @brief Setup identicon parameters.
*
* @param columns Number of columns
* @param rows Number of rows
* @param type The algorithm to use
* @param background Background color, hexadecimal, rrggbbaa
* @param foreground Array of foreground colors
* @param foreground_len Length of the array of foreground colors
* @param padding Padding in pixels { left & right, top & down }
*
* @return false on error, true otherwise.
*
* @since before 0.5.0
*/
bool identiconpp_setup(const uint8_t columns, const uint8_t rows,
identiconpp_algorithm type,
const char background[9],
const char foreground[][9],
const uint8_t foreground_len,
const uint8_t padding[2]);
/*!
* @brief Generates identicon from digest.
*
* @param magick See http://imagemagick.org/script/formats.php
* @param digest The pre-computed digest
* @param width The width of the identicon
*
* @return Length of the generated base64-string, or 0 on error.
*
* @since before 0.5.0
*/
uint64_t identiconpp_generate(const char magick[],
const char digest[], const uint16_t width);
/*!
* @brief Return base64-encoded string of the image generated with
* identiconpp_generate().
*
* @since before 0.5.0
*/
const char *identiconpp_base64();
#ifdef __cplusplus
}
#endif
#endif // IDENTICONPP_C_H

76
tests/test_c.cpp Normal file
View File

@ -0,0 +1,76 @@
#include <catch.hpp>
#include <string>
#include <exception>
#include <vector>
#include <cstdint>
#include <Magick++/Image.h>
#include "identiconpp_c.h"
using std::string;
using std::uint8_t;
using std::uint64_t;
SCENARIO("C interface", "[C]")
{
GIVEN("The digest: sha256(test@example.com)")
{
char digest[65] = "973dfe463ec85785f5f95af5ba3906ee"
"db2d931c24e69824a89ea65dba4e813b";
const uint8_t padding[2] = { 20, 40 };
bool success = false;
WHEN("256 bits of entropy is required")
{
const char colors[15][9] =
{
"000000ff", "000000ff", "000000ff", "000000ff", "000000ff",
"000000ff", "000000ff", "000000ff", "000000ff", "000000ff",
"000000ff", "000000ff", "000000ff", "000000ff", "000000ff"
};
success = identiconpp_setup(18, 28,
identiconpp_ltr_symmetric,
"ffffffff",
colors, 15, padding);
uint64_t len = identiconpp_generate("png", digest, 50);
if (len == 0)
{
success = false;
}
if (string(identiconpp_base64()).length() != len)
{
success = false;
}
THEN("Does not crash")
{
REQUIRE(success == true);
}
}
WHEN("257 bits of entropy is required")
{
const char colors[16][9] =
{
"000000ff", "000000ff", "000000ff", "000000ff", "000000ff",
"000000ff", "000000ff", "000000ff", "000000ff", "000000ff",
"000000ff", "000000ff", "000000ff", "000000ff", "000000ff",
"000000ff"
};
success = identiconpp_setup(18, 28,
identiconpp_ltr_symmetric,
"ffffffff",
colors, 16, padding);
if (identiconpp_generate("png", digest, 50) == 0)
{
success = false;
}
THEN("Crashes")
{
REQUIRE(success == false);
}
}
}
}