Compare commits

...

92 Commits

Author SHA1 Message Date
tastytea 9070f154a4
Version bump 0.7.3.
continuous-integration/drone/push Build is passing Details
2020-10-24 11:30:43 +02:00
tastytea b172c3cb3c
Generate package for Debian buster.
continuous-integration/drone/push Build was killed Details
2020-10-24 11:29:50 +02:00
tastytea e73a7625a6
Disable automatic RPM generation. 2020-10-24 10:26:12 +02:00
tastytea d283e1ebc9
Version bump 0.7.2. 2020-10-24 10:22:05 +02:00
tastytea 23f8f69e0e
Fix Debian package generation.
continuous-integration/drone/push Build was killed Details
2020-10-24 10:14:45 +02:00
tastytea 941f272f60
Remove copyright from readme. 2020-10-24 09:59:21 +02:00
tastytea 051cc273b7
Put name of distribution and version in generated packages.
continuous-integration/drone/push Build is passing Details
2020-10-24 09:54:01 +02:00
tastytea 9ed41d6ac8
Clarify that the binary packages are for Debian and CentOS. 2020-10-24 09:49:20 +02:00
tastytea 319a432309
Update editorconfig.
continuous-integration/drone/push Build is passing Details
2020-10-24 09:44:56 +02:00
tastytea 4d9dc6d8a7
Merge branch 'develop'
continuous-integration/drone/push Build is passing Details
2019-09-27 07:38:11 +02:00
tastytea 6e5eb38ed6
Fixed RPM dependencies.
continuous-integration/drone/push Build is passing Details
2019-09-27 07:26:32 +02:00
tastytea 27f95a25b2
Replaced README.md with README.adoc. 2019-09-27 07:26:26 +02:00
tastytea d4e325d75f
Make more use of variables in contribution guidelines.
continuous-integration/drone/push Build is passing Details
2019-09-27 04:09:08 +02:00
tastytea 81a4e335bb
Fix coc contact. 2019-09-27 04:08:20 +02:00
tastytea 341a0844f6
Add email to contributing guidelines, link to them in readme.
continuous-integration/drone/push Build is passing Details
2019-09-23 19:22:04 +02:00
tastytea f125f5e5d6
Merge branch 'develop' 2019-09-23 19:16:10 +02:00
tastytea c97d0f6307
Add COC, contributing guidelines and EditorConfig.
continuous-integration/drone/push Build is passing Details
2019-09-23 19:14:17 +02:00
tastytea 607e238698
Version bump 0.7.1.
continuous-integration/drone/push Build is passing Details
2019-09-23 19:02:33 +02:00
tastytea 7f99945719
Merge branch 'develop' 2019-09-23 19:02:13 +02:00
tastytea f7b2c22c23
Install header.
continuous-integration/drone/push Build was killed Details
2019-09-23 19:00:52 +02:00
tastytea 62542e4230
CI: Rename step clang6 → clang7.
continuous-integration/drone/push Build is passing Details
2019-09-13 19:15:10 +02:00
tastytea 1724c6d944
Version bump 0.7.0.
continuous-integration/drone/push Build is passing Details
2019-09-13 19:10:22 +02:00
tastytea acfc65c442
Merge branch 'develop'
* Modernize CMake recipes.
* Move files around.
* Install identiconppConfig.cmake.
2019-09-13 19:08:06 +02:00
tastytea b1e25041d9
Added include dir for BUILD_INTERFACE.
continuous-integration/drone/push Build is passing Details
2019-09-13 18:57:48 +02:00
tastytea 8af793ac6a
CI: Test with clang-7 on buster.
continuous-integration/drone/push Build is failing Details
2019-09-13 18:54:06 +02:00
tastytea 752ebfface
Add include dir to library. 2019-09-13 18:53:05 +02:00
tastytea 2d1bac9c3f
Moved identiconpp.hpp to include/. 2019-09-13 18:48:47 +02:00
tastytea d6c640698c
Modernized CMake recipes and moved files around. 2019-09-13 18:45:30 +02:00
tastytea 7e1dad0cf7
Add 2019 to copyright notice.
continuous-integration/drone/push Build is failing Details
2019-09-13 17:26:30 +02:00
tastytea 2477483517
Fix description in pkg-config recipe. 2019-09-13 17:19:32 +02:00
tastytea 74f55707f8
Remove unnecessary includes in CMake recipe.
continuous-integration/drone/push Build is failing Details
2019-09-13 16:59:15 +02:00
tastytea 4afee87285
Remove C support.
I'm not willing to invest the time to make it good.
2019-09-13 16:45:40 +02:00
tastytea 34eedfe6d1
Fix rpm package generation.
continuous-integration/drone/push Build is passing Details
* Set CXX for CentOS in CI correctly.
* Install the right ImageMagick.
* Fix gpg call.
* Fixed signature path.
2019-07-30 14:50:37 +02:00
tastytea 904313abd9
Version bump 0.6.1.
continuous-integration/drone/push Build is passing Details
2019-07-30 13:51:58 +02:00
tastytea 6f92a3625f
Updated readme.
continuous-integration/drone/push Build is passing Details
2019-07-30 13:41:16 +02:00
tastytea eb493d5c00
Whitesapace cleanup.
continuous-integration/drone/push Build is passing Details
2019-07-30 13:07:45 +02:00
tastytea 1f23390623
Added pkg-config file. 2019-07-30 13:04:08 +02:00
tastytea e5e4524947
Fixed header locations in cmake recipe.
continuous-integration/drone/push Build is passing Details
2019-07-30 12:27:17 +02:00
tastytea 04ccca4658
Updated drone config. 2019-07-30 12:26:35 +02:00
tastytea f6c82a321c
Simplyfied doxygen config. 2019-07-30 11:33:35 +02:00
tastytea 0ca6906cb5
Updated and modularized cmake recipes. 2019-07-30 11:32:57 +02:00
tastytea e6b5de0118
Moved tests. 2019-07-30 11:32:34 +02:00
tastytea 6b1b16304f
Changed padding to not have const uint8_t.
the build was successful Details
2019-02-20 23:02:09 +01:00
tastytea 588ec1b44c
Added tests for C interface
the build was successful Details
2019-01-18 15:55:13 +01:00
tastytea fb6eadd946
Added generate_base64()
the build was successful Details
2019-01-17 20:07:52 +01:00
tastytea d1a8dfd678
Fixed include guards
the build was successful Details
2019-01-07 13:54:37 +01:00
tastytea e7f64f9a61
Clarified contributing guidelines
the build was successful Details
2019-01-05 17:21:25 +01:00
tastytea 5e5ffb0343
Added C reference to readme.
the build was successful Details
2019-01-04 23:04:33 +01:00
tastytea 7868f42862
Added error reporting for the c interface.
the build was successful Details
2019-01-04 20:37:50 +01:00
tastytea dcf7317573
Enhanced documentation. 2019-01-04 20:35:28 +01:00
tastytea 8bb322edb9
Use friend class instead of protected members.
the build was successful Details
The reference got cluttered after I changed the private members to
protected.
2019-01-04 20:07:11 +01:00
tastytea 455eba820b
Initialize some variables.
They would have never been left unitialized, but the compiler didn't
know that.
2019-01-04 20:06:00 +01:00
tastytea ccbdb5c582
Added C interface to readme
the build was successful Details
2019-01-04 19:37:51 +01:00
tastytea 5be366f3cb
Added documentation to identiconpp_base64(). 2019-01-04 19:13:38 +01:00
tastytea da2b64b159
Merge branch 'c-interface' 2019-01-04 19:11:10 +01:00
tastytea 7cd528bea1
Added C-header to install recipe. 2019-01-04 19:10:59 +01:00
tastytea 28d08342d3
C-interface: Added more error checking. 2019-01-04 19:10:01 +01:00
tastytea cef436faf5
C-interface: Added example 2019-01-04 19:00:16 +01:00
tastytea 7c8a88bc6b
typo 2019-01-04 18:10:02 +01:00
tastytea 7d89f416e8
C-interface: return images as base64.
the build was successful Details
I couldn't figure out how to return them as MagickWand, maybe I can't
mix Magick++ with MagickWand.
2019-01-04 17:36:10 +01:00
tastytea 988eaf406c
Started C interface. 2019-01-03 13:28:53 +01:00
tastytea 91575c7775
Removed unnecessary includes 2019-01-03 10:16:38 +01:00
tastytea edaae3906b
typo 2019-01-03 10:07:46 +01:00
tastytea 356510adc9
Added include guards. 2019-01-03 08:37:00 +01:00
tastytea 9d784d18b1
Changed example, generated example images using example.
the build was successful Details
2019-01-03 08:20:36 +01:00
tastytea 6c8e8f336d
Added tests for not_hex().
the build was successful Details
2019-01-02 17:36:53 +01:00
tastytea 6e7bfed912
Added tests for check_entropy 2019-01-02 16:43:13 +01:00
tastytea 97ced01ffa
Added tags 2019-01-02 15:48:18 +01:00
tastytea 55de144050
Added color format tests.
the build was successful Details
2019-01-02 11:21:54 +01:00
tastytea 86e865edfe
Allow uppercase hex digits. 2019-01-02 11:18:43 +01:00
tastytea 04b7a3afd0
Added check for at least one foreground color. 2019-01-02 11:16:39 +01:00
tastytea 4b198ccd58
Added crash / don't crash tests.
the build was successful Details
2019-01-02 10:30:26 +01:00
tastytea ddd55f6221
Added color-size check to sigil algorithm. 2019-01-02 10:29:27 +01:00
tastytea 4e5397a2a2
Added color tests 2019-01-02 09:29:46 +01:00
tastytea dbb15bee87
Refined test compilation 2019-01-02 09:01:32 +01:00
tastytea a09bd56a2f
typo
the build was successful Details
2019-01-02 06:57:46 +01:00
tastytea ffff29d087
clarify that catch is for tests
the build was successful Details
2019-01-02 06:33:43 +01:00
tastytea 3faff570a2
If Catch 2 and Catch 1 is not found, then abort.
the build failed Details
2019-01-02 06:31:50 +01:00
tastytea a72149221a
Fixed CI recipe, confirmed support for Catch < 2
the build was successful Details
2019-01-02 06:18:36 +01:00
tastytea 3c879d6eb4
CI: Loop through tests
the build failed Details
2019-01-02 06:09:44 +01:00
tastytea e568a64129
Bugfix: Background color was always transparent with older imagemagick
the build was successful Details
versions
2019-01-02 06:01:16 +01:00
tastytea b0c0e0ef09
Added compatibility for Catch < 2, hopefully.
the build failed Details
2019-01-01 17:57:34 +01:00
tastytea 0e3d1e4691
Enabled tests in CI.
the build failed Details
2019-01-01 16:51:41 +01:00
tastytea 903de5f906
Added first tests.
the build was successful Details
2019-01-01 16:46:17 +01:00
tastytea b518d5ed12
Fixed entropy calculation for sigil. 2019-01-01 16:40:34 +01:00
tastytea 2fb09294e4
Added example to HTML reference.
the build was successful Details
2018-12-28 02:38:25 +01:00
tastytea dc6e32fbf9
Improved documentation, added images.
the build was successful Details
2018-12-28 02:02:26 +01:00
tastytea 211b0ba7b4
Fixed error: Would crash often if only one foreground color.
the build was successful Details
2018-12-28 01:42:22 +01:00
tastytea f891679884
Fixed algorithm descriptions in readme.
the build was successful Details
2018-12-27 23:23:24 +01:00
tastytea 35a1cc2233
Throw exception if width or height - padding * 2 is 0 or less.
the build was successful Details
2018-12-27 23:18:06 +01:00
tastytea 0425ee3fec
Corrected height calculation, floored log2-output explicitly.
the build was successful Details
2018-12-27 22:28:53 +01:00
tastytea 36dd2b7e5a
Corrected the "how many bits do i need for n colors"-algorithm.
the build was successful Details
2018-12-27 21:56:50 +01:00
34 changed files with 1909 additions and 699 deletions

View File

@ -1,198 +1,211 @@
pipeline:
gcc5:
image: debian:stretch-slim
pull: true
when:
event: [push, pull_request]
environment:
- LANG=C.utf8
- CXX=g++-5
- CXXFLAGS=-pipe -O2
commands:
- rm /etc/apt/apt.conf.d/docker-clean
- apt-get update -q
- echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release
- echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu xenial main" >> /etc/apt/sources.list.d/ubuntu-toolchain-r.list
- apt-get install -qy gnupg
- gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 0x60c317803a41ba51845e371a1e9377a2ba9ef27f
- gpg --armor --export 0x60c317803a41ba51845e371a1e9377a2ba9ef27f | apt-key add -
- apt-get update -q
- apt-get install -qy -t xenial g++-5
- apt-get install -qy cmake pkg-config
- apt-get install -qy libmagick++-dev
- rm -rf build && mkdir -p build && cd build
- cmake -DCMAKE_INSTALL_PREFIX=/usr ..
- make VERBOSE=1
volumes:
- /var/cache/debian-package-cache:/var/cache/apt/archives
# -*- fill-column: 1000 -*-
kind: pipeline
name: build x86_64
gcc6:
image: debian:stretch-slim
pull: true
environment:
- LANG=C.utf8
- CXX=g++-6
- CXXFLAGS=-pipe -O2
commands:
- rm /etc/apt/apt.conf.d/docker-clean
- apt-get update -q
- apt-get install -qy g++-6 cmake pkg-config
- apt-get install -qy libmagick++-dev
- apt-get install -qy dpkg-dev d-shlibs rpm file wget
- gpg --no-tty --import /var/autosign_gpg.key
- rm -rf build && mkdir -p build && cd build
- cmake -DCMAKE_INSTALL_PREFIX=/usr ..
- make VERBOSE=1
- make install DESTDIR=install
- make package
- cmake -DWITH_DEB=ON ..
- make package
- cmake -DWITH_DEB=OFF -DWITH_RPM=ON ..
- make package
- gpg --verbose --detach-sign *.tar.gz
- gpg --verbose --detach-sign *.deb
- gpg --verbose --detach-sign *.rpm
volumes:
- /var/cache/debian-package-cache:/var/cache/apt/archives
- /home/tastytea/misc/autosign_gpg.key:/var/autosign_gpg.key
volumes:
- name: debian-package-cache
host:
path: /var/cache/debian-package-cache
gcc7:
image: debian:stretch-slim
pull: true
when:
event: [push, pull_request]
environment:
- LANG=C.utf8
- CXX=g++-7
- CXXFLAGS=-pipe -O2
commands:
- rm /etc/apt/apt.conf.d/docker-clean
- apt-get update -q
- echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release
- echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu xenial main" >> /etc/apt/sources.list.d/ubuntu-toolchain-r.list
- apt-get install -qy gnupg
- gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 0x60c317803a41ba51845e371a1e9377a2ba9ef27f
- gpg --armor --export 0x60c317803a41ba51845e371a1e9377a2ba9ef27f | apt-key add -
- apt-get update -q
- apt-get install -qy -t xenial g++-7
- apt-get install -qy cmake pkg-config
- apt-get install -qy libmagick++-dev
- rm -rf build && mkdir -p build && cd build
- cmake -DCMAKE_INSTALL_PREFIX=/usr ..
- make VERBOSE=1
volumes:
- /var/cache/debian-package-cache:/var/cache/apt/archives
trigger:
event:
exclude:
- tag
gcc8:
image: debian:stretch-slim
pull: true
when:
event: [push, pull_request]
environment:
- LANG=C.utf8
- CXX=g++-8
- CXXFLAGS=-pipe -O2
commands:
- rm /etc/apt/apt.conf.d/docker-clean
- apt-get update -q
- echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release
- echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu xenial main" >> /etc/apt/sources.list.d/ubuntu-toolchain-r.list
- apt-get install -qy gnupg
- gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 0x60c317803a41ba51845e371a1e9377a2ba9ef27f
- gpg --armor --export 0x60c317803a41ba51845e371a1e9377a2ba9ef27f | apt-key add -
- apt-get update -q
- apt-get install -qy -t xenial g++-8
- apt-get install -qy cmake pkg-config
- apt-get install -qy libmagick++-dev
- rm -rf build && mkdir -p build && cd build
- cmake -DCMAKE_INSTALL_PREFIX=/usr ..
- make VERBOSE=1
volumes:
- /var/cache/debian-package-cache:/var/cache/apt/archives
steps:
- name: gcc6
image: debian:stretch-slim
pull: always
environment:
CXX: g++-6
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 g++-6 cmake pkg-config libmagick++-dev catch
- rm -rf build && mkdir -p build && cd build
- cmake -DWITH_TESTS=YES ..
- cmake --build .
- make install DESTDIR=install
- cd tests && ctest -V
volumes:
- name: debian-package-cache
path: /var/cache/apt/archives
clang5:
image: debian:stretch-slim
pull: true
when:
event: [push, pull_request]
environment:
- LANG=C.utf8
- CXX=clang++-5.0
- CXXFLAGS=-pipe -O2
commands:
- rm /etc/apt/apt.conf.d/docker-clean
- 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 -t stretch-backports clang-5.0
- apt-get install -qy cmake pkg-config
- apt-get install -qy libmagick++-dev
- rm -rf build && mkdir -p build && cd build
- cmake -DCMAKE_INSTALL_PREFIX=/usr ..
- make VERBOSE=1
volumes:
- /var/cache/debian-package-cache:/var/cache/apt/archives
- name: gcc9
image: debian:stretch-slim
pull: always
environment:
CXX: g++-9
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
- echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release
- echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu xenial main" >> /etc/apt/sources.list.d/ubuntu-toolchain-r.list
- apt-get install -qy gnupg
- gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 0x60c317803a41ba51845e371a1e9377a2ba9ef27f
- gpg --armor --export 0x60c317803a41ba51845e371a1e9377a2ba9ef27f | apt-key add -
- apt-get update -q
- apt-get install -qy -t xenial g++-9
- apt-get install -qy cmake pkg-config libmagick++-dev
- rm -rf build && mkdir -p build && cd build
- cmake ..
- cmake --build .
volumes:
- name: debian-package-cache
path: /var/cache/apt/archives
clang6:
image: debian:stretch-slim
pull: true
when:
event: [push, pull_request]
environment:
- LANG=C.utf8
- CXX=clang++-6.0
- CXXFLAGS=-pipe -O2
commands:
- rm /etc/apt/apt.conf.d/docker-clean
- 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 -t stretch-backports clang-6.0
- apt-get install -qy cmake pkg-config
- apt-get install -qy libmagick++-dev
- rm -rf build && mkdir -p build && cd build
- cmake -DCMAKE_INSTALL_PREFIX=/usr ..
- make VERBOSE=1
volumes:
- /var/cache/debian-package-cache:/var/cache/apt/archives
- name: clang7
image: debian:buster-slim
pull: always
environment:
CXX: clang++
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 clang cmake pkg-config libmagick++-dev
- rm -rf build && mkdir -p build && cd build
- cmake ..
- cmake --build .
volumes:
- name: debian-package-cache
path: /var/cache/apt/archives
prepare_release:
image: debian:stretch-slim
pull: true
when:
event: tag
commands:
- cp -v build/identiconpp-${DRONE_TAG}_x86_64.tar.gz .
- cp -v build/identiconpp-${DRONE_TAG}_x86_64.tar.gz.sig .
- cp -v build/identiconpp_${DRONE_TAG}-0_amd64.deb .
- cp -v build/identiconpp_${DRONE_TAG}-0_amd64.deb.sig .
- cp -v build/identiconpp-${DRONE_TAG}-0.x86_64.rpm .
- cp -v build/identiconpp-${DRONE_TAG}-0.x86_64.rpm.sig .
---
kind: pipeline
name: packages x86_64
gitea_release:
image: plugins/gitea-release
pull: true
when:
event: tag
volumes:
- name: debian-package-cache
host:
path: /var/cache/debian-package-cache
- name: centos-package-cache
host:
path: /var/cache/centos-package-cache
- name: gpg-key
host:
path: /home/tastytea/misc/autosign_gpg.key
trigger:
event:
- tag
steps:
- name: Debian stretch
image: debian:stretch-slim
pull: always
environment:
CXX: g++-6
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 g++-6 cmake pkg-config libmagick++-dev gnupg dpkg-dev d-shlibs lsb-release
- 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 ..
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
pull: always
environment:
CXX: g++-8
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
- 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_buster.deb ..
- cp -v identiconpp_${DRONE_TAG}-0_amd64_buster.deb.sig ..
volumes:
- name: debian-package-cache
path: /var/cache/apt/archives
- 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
settings:
base_url: https://schlomp.space
secrets: [ gitea_token ]
api_key:
from_secret: gitea_token
title: ${DRONE_TAG}
prerelease: true
files:
- identiconpp-${DRONE_TAG}_x86_64.tar.gz
- identiconpp-${DRONE_TAG}_x86_64.tar.gz.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
- 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
checksum:
- sha512
notify:
image: drillster/drone-email
pull: true
- name: notify
image: drillster/drone-email
pull: always
settings:
host: cryptoparty-celle.de
secrets: [ email_username, email_password ]
from: drone@tzend.de
when:
status: [ changed, failure ]
username:
from_secret: email_username
password:
from_secret: email_password
when:
status: [ changed, failure ]

20
.editorconfig Normal file
View File

@ -0,0 +1,20 @@
# 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,43 +1,57 @@
cmake_minimum_required (VERSION 3.2)
project(identiconpp
VERSION 0.3.1
LANGUAGES CXX
)
# 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()
include(GNUInstallDirs)
find_package(PkgConfig REQUIRED)
pkg_check_modules(MAGICPP REQUIRED Magick++)
project(identiconpp
VERSION 0.7.3
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)
string(REPLACE ";" " " MAGICPP_CFLAGS_STRING "${MAGICPP_CFLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MAGICPP_CFLAGS_STRING}")
set(CMAKE_CXX_FLAGS_DEBUG
"${CMAKE_CXX_FLAGS_DEBUG} -Wall -pedantic -Wextra -g -Og -fno-omit-frame-pointer")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-DDEBUG=1)
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()
include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(${PROJECT_BINARY_DIR})
include_directories(${MAGICPP_INCLUDE_DIRS})
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-DDEBUG=1)
endif()
link_directories(${MAGICPP_LIBRARY_DIRS})
add_subdirectory(src)
add_subdirectory(include)
add_subdirectory(cmake)
add_subdirectory(pkg-config)
file(GLOB sources src/*.cpp)
add_library(${CMAKE_PROJECT_NAME} SHARED "${sources}")
set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${${CMAKE_PROJECT_NAME}_VERSION_MAJOR})
target_link_libraries(${CMAKE_PROJECT_NAME} "${MAGICPP_LDFLAGS}")
add_executable(example "example.cpp")
target_link_libraries(example ${CMAKE_PROJECT_NAME})
install(TARGETS ${CMAKE_PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES src/${CMAKE_PROJECT_NAME}.hpp DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES README.md DESTINATION ${CMAKE_INSTALL_DOCDIR})
if(WITH_TESTS)
add_subdirectory(tests)
endif()
include(packages.CMakeLists.txt)

49
CODE_OF_CONDUCT.adoc Normal file
View File

@ -0,0 +1,49 @@
: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

29
CONTRIBUTING.adoc Normal file
View File

@ -0,0 +1,29 @@
: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`.

192
Doxyfile
View File

@ -1,198 +1,28 @@
DOXYFILE_ENCODING = UTF-8
# -*- mode: conf-unix -*-
PROJECT_NAME = "identiconpp"
PROJECT_NUMBER = 0.0.0
INPUT = README.md src/
USE_MDFILE_AS_MAINPAGE = README.md
CREATE_SUBDIRS = NO
EXAMPLE_PATH = ./
EXAMPLE_RECURSIVE = YES
GENERATE_HTML = YES
HTML_OUTPUT = doc/html
GENERATE_LATEX = NO
ALLOW_UNICODE_NAMES = YES
OUTPUT_LANGUAGE = English
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ALWAYS_DETAILED_SEC = NO
ALWAYS_DETAILED_SEC = YES
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
MARKDOWN_SUPPORT = YES
AUTOLINK_SUPPORT = YES
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES
DISTRIBUTE_GROUP_DOC = NO
GROUP_NESTED_COMPOUNDS = NO
SUBGROUPING = YES
INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS = NO
TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_PACKAGE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
EXTRACT_ANON_NSPACES = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
HIDE_COMPOUND_REFERENCE= NO
SHOW_INCLUDE_FILES = YES
SHOW_GROUPED_MEMB_INC = NO
FORCE_LOCAL_INCLUDES = NO
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_MEMBERS_CTORS_1ST = NO
SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = NO
STRICT_PROTO_MATCHING = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_FILES = YES
SHOW_NAMESPACES = YES
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
INPUT_ENCODING = UTF-8
RECURSIVE = NO
EXCLUDE_SYMLINKS = NO
EXAMPLE_PATH = examples
EXAMPLE_RECURSIVE = YES
FILTER_SOURCE_FILES = NO
SOURCE_BROWSER = NO
INLINE_SOURCES = YES
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = NO
REFERENCES_RELATION = NO
REFERENCES_LINK_SOURCE = YES
SOURCE_TOOLTIPS = YES
USE_HTAGS = NO
BUILTIN_STL_SUPPORT = YES
VERBATIM_HEADERS = YES
CLANG_ASSISTED_PARSING = NO
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 5
GENERATE_HTML = YES
HTML_OUTPUT = doc/html
HTML_FILE_EXTENSION = .html
HTML_COLORSTYLE_HUE = 220
HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
HTML_TIMESTAMP = NO
HTML_DYNAMIC_SECTIONS = NO
HTML_INDEX_NUM_ENTRIES = 100
GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_BUNDLE_ID = org.doxygen.Project
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
DOCSET_PUBLISHER_NAME = Publisher
GENERATE_HTMLHELP = NO
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = NO
GENERATE_QHP = NO
QHP_NAMESPACE = org.doxygen.Project
QHP_VIRTUAL_FOLDER = doc
GENERATE_ECLIPSEHELP = NO
ECLIPSE_DOC_ID = org.doxygen.Project
DISABLE_INDEX = NO
GENERATE_TREEVIEW = NO
ENUM_VALUES_PER_LINE = 4
TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
USE_MATHJAX = NO
MATHJAX_FORMAT = HTML-CSS
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
SEARCHENGINE = NO
SERVER_BASED_SEARCH = NO
EXTERNAL_SEARCH = NO
SEARCHDATA_FILE = searchdata.xml
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4
PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_SOURCE_CODE = NO
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_SUBDIR =
MAN_LINKS = NO
GENERATE_XML = NO
XML_OUTPUT = xml
XML_PROGRAMLISTING = YES
GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook
DOCBOOK_PROGRAMLISTING = NO
GENERATE_AUTOGEN_DEF = NO
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
SKIP_FUNCTION_MACROS = YES
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
PERL_PATH = /usr/bin/perl
CLASS_DIAGRAMS = YES
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
DOT_NUM_THREADS = 0
DOT_FONTNAME = Helvetica
DOT_FONTSIZE = 10
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
UML_LIMIT_NUM_FIELDS = 10
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
CALLER_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
INTERACTIVE_SVG = NO
DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
INLINE_SOURCES = YES
SEARCHENGINE = YES
SHOW_FILES = YES

194
README.adoc Normal file
View File

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

177
README.md
View File

@ -1,177 +0,0 @@
**identiconpp** is a library to generate identicons. Written in C++.
You get the images as `Magick::Image`. This allows you to make all kinds of
modifications.
## 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.
### Example
```C++
// Compile with g++ $(Magick++-config --cppflags --ldflags) -lidenticonpp
#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");
}
```
## 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
* rpm
* tar.gz
They are generated on Debian Stretch 64 bit and signed with my
[automatic signing key](https://tastytea.de/tastytea_autosign.asc).
### From source
#### Dependencies
* C++ compiler (tested: [gcc](https://gcc.gnu.org/) 5/6/7/8,
[clang](https://llvm.org/) 5/6)
* [cmake](https://cmake.org/) (at least 3.2)
* [imagemagick](https://www.imagemagick.org/) (tested: 7.0 / 6.7)
On a Debian system, install the packages:
`build-essential cmake libmagick++-dev`.
#### Compile
```SH
mkdir build
cd build
cmake ..
make
make install
```
##### cmake options
* `-DCMAKE_BUILD_TYPE=Debug` for a debug build
* 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 or via
email to `tastytea`@`tastytea.de`.
## Contact
See https://tastytea.de/
## License & Copyright
```PLAIN
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.
* 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.
* 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,8 +1,7 @@
#!/bin/sh
#!/bin/bash
if [ -f Doxyfile ]; then
if [[ -f Doxyfile ]]; then
mkdir -p doc
(cat Doxyfile && echo -n "PROJECT_NUMBER = " &&
grep -Eo '[0-9]+.[0-9]+.[0-9]+$' CMakeLists.txt) \
| doxygen -
(doxygen -s -g - && cat Doxyfile && echo -n "PROJECT_NUMBER = " &&
grep -Eo '[0-9]+.[0-9]+.[0-9]+$' CMakeLists.txt) | doxygen -
fi

19
cmake/CMakeLists.txt Normal file
View File

@ -0,0 +1,19 @@
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

@ -0,0 +1,7 @@
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")

View File

@ -1,71 +0,0 @@
/* This file is part of identiconpp.
* Public Domain / CC-0
*
* Compile with g++ $(Magick++-config --cppflags --ldflags) -lidenticonpp
*/
#include <string>
#include <Magick++/Image.h>
#include "identiconpp.hpp"
int main(int argc, char *argv[])
{
string digest =
"973dfe463ec85785f5f95af5ba3906eedb2d931c24e69824a89ea65dba4e813b";
Magick::Image img;
if (argc > 1)
{
digest = argv[1];
}
{
Identiconpp identicon(5, 5, Identiconpp::algorithm::ltr_symmetric,
"ffffff80",
{
"000000ff",
"ff0000ff",
"ffff00ff",
"00ff00ff",
"00ffffff",
"0000ffff"
}, { 10, 10 });
img = identicon.generate(digest, 500);
img.write("identicon_example_ltr_symmetric.png");
}
{
Identiconpp identicon(5, 5, Identiconpp::algorithm::ltr_asymmetric,
"00000080",
{
"ffffffc0",
"ff0000c0",
"ffff00c0",
"00ff00c0",
"00ffffc0",
"0000ffc0"
});
img = identicon.generate(digest, 500);
img.write("identicon_example_ltr_asymmetric.png");
img.magick("GIF");
img.write("identicon_example_ltr_asymmetric.gif");
}
{
Identiconpp identicon(5, 5, Identiconpp::algorithm::sigil,
"ffffffff",
{
"000000ff",
"ff0000ff",
"ffff00ff",
"00ff00ff",
"00ffffff",
"0000ffff"
});
img = identicon.generate(digest, 500);
img.write("identicon_example_sigil.png");
img.write("identicon_example_sigil.jpg");
}
return 0;
}

4
examples/CMakeLists.txt Normal file
View File

@ -0,0 +1,4 @@
# 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)

62
examples/example.cpp Normal file
View File

@ -0,0 +1,62 @@
/* This file is part of identiconpp.
* Public Domain / CC-0
*
* Compile with g++ $(pkg-config --libs --cflags identiconpp)
*/
#include <string>
#include <vector>
#include "identiconpp.hpp"
#include <Magick++/Image.h>
int main(int argc, char *argv[])
{
// sha256(test@example.com)
std::string digest = "973dfe463ec85785f5f95af5ba3906ee"
"db2d931c24e69824a89ea65dba4e813b";
const std::vector<std::string> colors =
{
"800000ff",
"008000ff",
"000080ff",
"808000ff",
"008080ff",
"800080ff"
};
Magick::Image img;
if (argc > 1)
{
digest = argv[1];
}
{
Identiconpp identicon(4, 4, Identiconpp::algorithm::ltr_symmetric,
"ffffffff", colors, { 20, 20 });
img = identicon.generate(digest , 200);
img.write("identicon1.png");
}
{
Identiconpp identicon(5, 5, Identiconpp::algorithm::sigil,
"00000080", colors);
img = identicon.generate(digest , 200);
img.write("identicon2.png");
}
{
Identiconpp identicon(5, 5, Identiconpp::algorithm::ltr_asymmetric,
"000000ff", colors);
img = identicon.generate(digest , 200);
img.write("identicon3.png");
}
{
Identiconpp identicon(6, 4, Identiconpp::algorithm::ltr_symmetric,
"000000c0", colors, { 10, 10 });
img = identicon.generate(digest , 200);
img.write("identicon4.png");
}
return 0;
}

4
include/CMakeLists.txt Normal file
View File

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

View File

@ -1,5 +1,5 @@
/* This file is part of identiconpp.
* Copyright © 2018 tastytea <tastytea@tastytea.de>
* Copyright © 2018, 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
@ -14,6 +14,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef IDENTICONPP_HPP
#define IDENTICONPP_HPP
#include <cstdint>
#include <string>
#include <vector>
@ -26,6 +29,10 @@ using std::string;
using std::vector;
using std::array;
/*!
* @example example.cpp
*/
/*!
* @brief Base class for identiconpp.
*
@ -35,13 +42,21 @@ using std::array;
class Identiconpp
{
public:
friend class Testiconpp;
/*!
* @brief List of identicon algorithms
*/
enum class algorithm
{
//! Generates symmetric (vertically mirrored) identicons.
ltr_symmetric,
//! Generates asymmetric identicons.
ltr_asymmetric,
/*!
* Generates the same results as
* [sigil](https://github.com/cupcake/sigil/) and
* [pydenticon](https://github.com/azaghal/pydenticon/).
*/
sigil
};
@ -58,12 +73,14 @@ public:
* @param background Background color, hexadecimal, rrggbbaa
* @param foreground vector of foreground colors
* @param padding Padding in pixels { left & right, top & down }
*
* @since before 0.5.0
*/
explicit Identiconpp(const uint8_t columns, const uint8_t rows,
algorithm type = algorithm::ltr_symmetric,
const string &background = "ffffffff",
const vector<string> &foreground = { "000000ff" },
const array<const uint8_t, 2> &padding = { 0, 0 });
const array<uint8_t, 2> &padding = { 0, 0 });
/*!
* @brief Generates identicon from digest.
@ -72,16 +89,32 @@ public:
* @param width The width of the image in pixels
*
* @return The image as Magick::Image
*
* @since before 0.5.0
*/
Magick::Image generate(const string &digest, const uint16_t width = 100);
/*!
* @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 image in pixels
*
* @return The image as base64-string
*
* @since 0.5.0
*/
const string generate_base64(const string &magick, const string &digest,
const uint16_t width = 100);
private:
const uint8_t _rows;
const uint8_t _columns;
const algorithm _type;
const string _background;
const vector<string> _foreground;
const array<const uint8_t, 2> _padding;
const array<uint8_t, 2> _padding;
/*!
* @brief Generate ltr_symmetric identicon.
@ -93,6 +126,8 @@ private:
* @param digest The pre-computed digest
*
* @return The image
*
* @since before 0.5.0
*/
Magick::Image generate_ltr_symmetric(const string &digest);
@ -106,6 +141,8 @@ private:
* @param digest The pre-computed digest
*
* @return The image
*
* @since before 0.5.0
*/
Magick::Image generate_ltr_asymmetric(const string &digest);
@ -119,6 +156,8 @@ private:
* @param digest The pre-computed digest
*
* @return The image
*
* @since before 0.5.0
*/
Magick::Image generate_sigil(const string &digest);
@ -129,6 +168,8 @@ private:
*
* @param digest The pre-computed digest
* @param type The type of identicon
*
* @since before 0.5.0
*/
void check_entropy(const string &digest, algorithm type);
@ -139,6 +180,8 @@ private:
* @param digest The digest
*
* @return The bit.
*
* @since before 0.5.0
*/
bool get_bit(const uint16_t bit, const string &digest);
@ -151,6 +194,8 @@ private:
* @param digest The digest
*
* @return A foreground color.
*
* @since before 0.5.0
*/
Magick::Color get_color(const uint16_t firstbit, const string &digest);
@ -160,6 +205,8 @@ private:
* @param c Character to check
*
* @return true if not hex.
*
* @since before 0.5.0
*/
static bool not_hex(const char c);
@ -167,6 +214,10 @@ private:
* @brief Performs checks on a color definition in a string.
*
* @param color The color as string
*
* @since before 0.5.0
*/
void check_color(const string &color);
};
#endif // IDENTICONPP_HPP

View File

@ -4,42 +4,58 @@ set(CPACK_PACKAGE_VERSION_MAJOR ${${CMAKE_PROJECT_NAME}_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${${CMAKE_PROJECT_NAME}_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${${CMAKE_PROJECT_NAME}_VERSION_PATCH})
set(CPACK_PACKAGE_VERSION ${${CMAKE_PROJECT_NAME}_VERSION})
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Library to generate identicons. Written in C++.")
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.md")
set(CPACK_RESOURCE_FILE_README "${PROJECT_SOURCE_DIR}/README.adoc")
list(APPEND CPACK_SOURCE_IGNORE_FILES "/\\\\.git"
"/.gitignore"
"/build/"
"/doc/"
"\\\\.sublime-"
"/.drone.yml")
"/.gitignore"
"/build/"
"/doc/"
"/.drone.yml"
"/.dir-locals.el")
execute_process(COMMAND uname -m
OUTPUT_VARIABLE CPACK_PACKAGE_ARCHITECTURE
OUTPUT_STRIP_TRAILING_WHITESPACE)
OUTPUT_VARIABLE CPACK_PACKAGE_ARCHITECTURE
OUTPUT_STRIP_TRAILING_WHITESPACE)
set(CPACK_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}_${CPACK_PACKAGE_ARCHITECTURE}")
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}_${CPACK_PACKAGE_ARCHITECTURE}")
set(CPACK_GENERATOR "TGZ")
set(CPACK_SOURCE_GENERATOR "TGZ")
if (WITH_DEB)
set(CPACK_GENERATOR "DEB")
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://schlomp.space/tastytea/${CMAKE_PROJECT_NAME}")
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
execute_process(COMMAND dpkg --print-architecture
OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
OUTPUT_STRIP_TRAILING_WHITESPACE)
set(CPACK_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
set(CPACK_GENERATOR "DEB")
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE
"https://schlomp.space/tastytea/${CMAKE_PROJECT_NAME}")
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
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}")
endif()
if (WITH_RPM)
set(CPACK_GENERATOR "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++, libxdg-basedir >= 1.2.0")
set(CPACK_GENERATOR "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_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_NAME}-${CPACK_PACKAGE_VERSION}-0.${CPACK_PACKAGE_ARCHITECTURE}")
"${CPACK_PACKAGE_FILE_NAME}.centos${OS_RELEASE}")
endif()
endif()
include(CPack)

View File

@ -0,0 +1,7 @@
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

@ -0,0 +1,12 @@
name=@PROJECT_NAME@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
Name: ${name}
Description: @PROJECT_DESCRIPTION@
Version: @PROJECT_VERSION@
Libs: -L${libdir} -l${name}
Cflags: -I${includedir}
Requires: Magick++

25
src/CMakeLists.txt Normal file
View File

@ -0,0 +1,25 @@
include(GNUInstallDirs)
find_package(PkgConfig REQUIRED)
pkg_check_modules(Magick++ REQUIRED IMPORTED_TARGET Magick++)
file(GLOB sources *.cpp)
add_library(${PROJECT_NAME}
${sources} ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}.hpp)
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})

View File

@ -17,6 +17,7 @@
#include <exception>
#include <stdexcept>
#include <algorithm>
#include <cmath>
#include "identiconpp.hpp"
#include "debug.hpp"
@ -26,12 +27,12 @@ void Identiconpp::check_entropy(const string &digest, algorithm type)
{
throw std::invalid_argument
(
"Colors must consist of hexadecimal digits (" + digest + ")."
"Digests must consist of hexadecimal digits (" + digest + ")."
);
}
uint16_t entropy_provided;
uint16_t entropy_required;
uint16_t entropy_provided = 0;
uint16_t entropy_required = 0;
switch (type)
{
case algorithm::ltr_symmetric:
@ -41,19 +42,24 @@ void Identiconpp::check_entropy(const string &digest, algorithm type)
// We need bits for each field in half of the columns, +1 column if
// they are uneven. Then we need enough bits to pick a color.
entropy_required = (_columns / 2 + _columns % 2) * _rows
+ (_foreground.size() / 2 + _foreground.size() % 2);
+ std::floor(std::log2(_foreground.size())) + 1;
break;
}
case algorithm::ltr_asymmetric:
{
entropy_provided = digest.length() * 4;
entropy_required = _columns * _rows
+ (_foreground.size() / 2 + _foreground.size() % 2);
+ std::floor(std::log2(_foreground.size())) + 1;
break;
}
case algorithm::sigil:
{
entropy_provided = digest.length() / 2 * 8;
if (_foreground.size() > 256)
{
throw std::invalid_argument(
"sigil algorithm does not support more than 256 colors.");
}
entropy_provided = digest.length() * 4;
entropy_required = (_columns / 2 + _columns % 2) * _rows + 8;
break;
}
@ -75,6 +81,10 @@ bool Identiconpp::not_hex(const char c)
{ // a-f
return false;
}
if (c >= 0x41 && c <= 0x46)
{ // A-F
return false;
}
if (c >= 0x30 && c <= 0x39)
{ // 0-9
return false;

View File

@ -1,6 +1,6 @@
/* This file is part of identiconpp.
* Copyright © 2018 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.
@ -18,9 +18,6 @@
#define DEBUG_HPP
#include <iostream>
#include <exception>
#include <stdexcept>
#include <sstream>
#ifdef DEBUG
#define ttdebug std::cerr << "[" << __FILE__ << ":" << __LINE__ << "] DEBUG: "

View File

@ -17,6 +17,8 @@
#include <exception>
#include <stdexcept>
#include <sstream>
#include <cmath>
#include <Magick++/Blob.h>
#include "identiconpp.hpp"
#include "debug.hpp"
@ -24,7 +26,7 @@ Identiconpp::Identiconpp(const uint8_t columns, const uint8_t rows,
algorithm type,
const string &background,
const vector<string> &foreground,
const array<const uint8_t, 2> &padding)
const array<uint8_t, 2> &padding)
: _rows(rows)
, _columns(columns)
, _type(type)
@ -32,23 +34,38 @@ Identiconpp::Identiconpp(const uint8_t columns, const uint8_t rows,
, _foreground(foreground)
, _padding(padding)
{
check_color(background);
check_color(_background);
for (const string &color : foreground)
for (const string &color : _foreground)
{
check_color(color);
}
if (_foreground.size() == 0)
{
throw std::invalid_argument
(
"You must specify at least 1 foreground color."
);
}
}
Magick::Image Identiconpp::generate(const string &digest, const uint16_t width)
{
ttdebug << "Using digest: " << digest << '\n';
check_entropy(digest, _type);
const uint16_t imgwidth = width - _padding[0] * 2;
const uint16_t imgheight = imgwidth / _columns * _rows;
ttdebug << "width: " << std::to_string(imgwidth + _padding[0] * 2)
<< ", height: " << std::to_string(imgheight + _padding[1] * 2)
const std::int16_t imgwidth = width - _padding[0] * 2;
const std::int16_t imgheight =
std::round(static_cast<float>(imgwidth) / _columns * _rows);
ttdebug << "width: " << std::to_string(imgwidth)
<< "+" << std::to_string(_padding[0] * 2)
<< ", height: " << std::to_string(imgheight)
<< "+" << std::to_string(_padding[1] * 2)
<< "\n";
if (imgwidth <= 0 || imgheight <= 0)
{
throw std::invalid_argument("Width or height is zero or less.");
}
Magick::Image img;
switch (_type)
@ -70,13 +87,26 @@ Magick::Image Identiconpp::generate(const string &digest, const uint16_t width)
}
}
img.backgroundColor(Magick::Color('#' + _background));
img.scale(Magick::Geometry(imgwidth, imgheight));
img.borderColor(Magick::Color('#' + _background));
img.border(Magick::Geometry(_padding[0], _padding[1]));
// The CompositeOperator prevents the background color to be affected by the
// frame color. See https://github.com/ImageMagick/ImageMagick/issues/647
img.compose(Magick::CompositeOperator::CopyCompositeOp);
img.matteColor(Magick::Color('#' + _background));
img.frame(Magick::Geometry(_padding[0], _padding[1]));
return img;
}
const string Identiconpp::generate_base64(const string &magick,
const string &digest,
const uint16_t width)
{
Magick::Image img = generate(digest, width);
Magick::Blob blob;
img.magick(magick);
img.write(&blob);
return blob.base64();
}
bool Identiconpp::get_bit(const uint16_t bit, const string &digest)
{
std::stringstream ss;
@ -100,7 +130,7 @@ Magick::Color Identiconpp::get_color(const uint16_t firstbit,
const string &digest)
{
// Number of bits to use
const uint16_t colorbits = _foreground.size() / 2 + _foreground.size() % 2;
const uint16_t colorbits = std::floor(std::log2(_foreground.size())) + 1;
// Extract approximation
std::stringstream ss;
@ -115,7 +145,7 @@ Magick::Color Identiconpp::get_color(const uint16_t firstbit,
// std::stringstream does not support writing into uint16_t
unsigned short bits;
ss >> bits;
// Shift an one $colorbits times to the left, substract 1. This leaves us
// with $colorbits ones. Then AND bits and our ones to keep only as many
// bits as we need.
@ -125,7 +155,7 @@ Magick::Color Identiconpp::get_color(const uint16_t firstbit,
// a power of 2.
if (bits > (_foreground.size() - 1))
{
bits -= (_foreground.size() - 1);
bits -= _foreground.size();
}
// Lookup und set color

View File

@ -20,7 +20,7 @@
Magick::Image Identiconpp::generate_ltr_asymmetric(const string &digest)
{
Magick::Image img(Magick::Geometry(_columns, _rows),
Magick::Color("#00000000"));
Magick::Color('#' + _background));
Magick::Color dotcolor = get_color(_columns * _rows + 1, digest);
for (uint8_t row = 0; row < _rows; ++row)

View File

@ -20,7 +20,7 @@
Magick::Image Identiconpp::generate_ltr_symmetric(const string &digest)
{
Magick::Image img(Magick::Geometry(_columns, _rows),
Magick::Color("#00000000"));
Magick::Color('#' + _background));
uint8_t used_columns = _columns / 2 + _columns % 2;
Magick::Color dotcolor = get_color(used_columns * _rows + 1, digest);

View File

@ -20,7 +20,7 @@
Magick::Image Identiconpp::generate_sigil(const string &digest)
{
Magick::Image img(Magick::Geometry(_columns, _rows),
Magick::Color("#00000000"));
Magick::Color('#' + _background));
Magick::Color dotcolor = get_color(0, digest);
uint8_t used_columns = _columns / 2 + _columns % 2;

24
tests/CMakeLists.txt Normal file
View File

@ -0,0 +1,24 @@
include(CTest)
file(GLOB sources_tests test_*.cpp)
find_package(Catch2)
if(Catch2_FOUND) # Catch 2.x
include(Catch)
add_executable(all_tests main.cpp ${sources_tests})
target_link_libraries(all_tests Catch2::Catch2 ${PROJECT_NAME})
target_include_directories(all_tests PRIVATE "/usr/include/catch2")
catch_discover_tests(all_tests EXTRA_ARGS "${EXTRA_TEST_ARGS}")
else() # Catch 1.x
if(EXISTS "/usr/include/catch.hpp")
message(STATUS "Catch 1.x found.")
foreach(src ${sources_tests})
get_filename_component(bin ${src} NAME_WE)
add_executable(${bin} main.cpp ${src})
target_link_libraries(${bin} ${PROJECT_NAME})
add_test(${bin} ${bin} "${EXTRA_TEST_ARGS}")
endforeach()
else()
message(FATAL_ERROR
"Neither Catch 2.x nor Catch 1.x could be found.")
endif()
endif()

2
tests/main.cpp Normal file
View File

@ -0,0 +1,2 @@
#define CATCH_CONFIG_MAIN
#include <catch.hpp>

View File

@ -0,0 +1,166 @@
#include <catch.hpp>
#include <string>
#include <vector>
#include <exception>
#include "identiconpp.hpp"
using std::string;
class Testiconpp : private Identiconpp
{
public:
explicit Testiconpp(const uint8_t columns, const uint8_t rows,
const Identiconpp::algorithm &type,
const vector<string> &foreground = { "000000ff" })
: Identiconpp(columns, rows, type, "ffffffff", foreground) {};
bool test_check_entropy(const string &digest)
{
try
{
check_entropy(digest, _type);
}
catch (const std::exception &e)
{
return false;
}
return true;
}
};
SCENARIO("Entropy checks: ltr_symmetric", "[checks][ltr_symmetric]")
{
WHEN("An Identiconpp instance with 1x3 dots")
{
Testiconpp testicon(1, 3, Identiconpp::algorithm::ltr_symmetric);
THEN("Required entropy is <= 4")
{
REQUIRE(testicon.test_check_entropy("f"));
}
}
WHEN("An Identiconpp instance with 14x1 dots")
{
Testiconpp testicon(14, 1, Identiconpp::algorithm::ltr_symmetric);
THEN("Required entropy is <= 8")
{
REQUIRE(testicon.test_check_entropy("ff"));
}
}
WHEN("An Identiconpp instance with 255x255 dots")
{
Testiconpp testicon(255, 255, Identiconpp::algorithm::ltr_symmetric);
THEN("Required entropy is <= 32644")
{
string digest(8161, 'c');
REQUIRE(testicon.test_check_entropy(digest));
}
}
WHEN("An Identiconpp instance with 7 colors")
{
std::vector<string> colors(7, "000000ff");
Testiconpp testicon(1, 1, Identiconpp::algorithm::ltr_symmetric,
colors);
THEN("Required entropy is <= 4")
{
REQUIRE(testicon.test_check_entropy("f"));
}
}
WHEN("An Identiconpp instance with 524287 colors")
{
std::vector<string> colors(524287, "000000ff");
Testiconpp testicon(1, 1, Identiconpp::algorithm::ltr_symmetric,
colors);
THEN("Required entropy is <= 20")
{
REQUIRE(testicon.test_check_entropy("fffff"));
}
}
}
SCENARIO("Entropy checks: ltr_asymmetric", "[checks][ltr_asymmetric]")
{
WHEN("An Identiconpp instance with 3x1 dots")
{
Testiconpp testicon(3, 1, Identiconpp::algorithm::ltr_asymmetric);
THEN("Required entropy is <= 4")
{
REQUIRE(testicon.test_check_entropy("f"));
}
}
WHEN("An Identiconpp instance with 14x1 dots")
{
Testiconpp testicon(1, 7, Identiconpp::algorithm::ltr_asymmetric);
THEN("Required entropy is <= 8")
{
REQUIRE(testicon.test_check_entropy("ff"));
}
}
WHEN("An Identiconpp instance with 255x255 dots")
{
Testiconpp testicon(255, 255, Identiconpp::algorithm::ltr_asymmetric);
THEN("Required entropy is <= 65028")
{
string digest(16257, 'c');
REQUIRE(testicon.test_check_entropy(digest));
}
}
WHEN("An Identiconpp instance with 7 colors")
{
std::vector<string> colors(7, "000000ff");
Testiconpp testicon(1, 1, Identiconpp::algorithm::ltr_asymmetric,
colors);
THEN("Required entropy is <= 4")
{
REQUIRE(testicon.test_check_entropy("f"));
}
}
WHEN("An Identiconpp instance with 524287 colors")
{
std::vector<string> colors(524287, "000000ff");
Testiconpp testicon(1, 1, Identiconpp::algorithm::ltr_asymmetric,
colors);
THEN("Required entropy is <= 20")
{
REQUIRE(testicon.test_check_entropy("fffff"));
}
}
}
SCENARIO("Entropy checks: sigil", "[checks][sigil]")
{
WHEN("An Identiconpp instance with 4x2 dots")
{
Testiconpp testicon(4, 2, Identiconpp::algorithm::sigil);
THEN("Required entropy is <= 12")
{
REQUIRE(testicon.test_check_entropy("fff"));
}
}
WHEN("An Identiconpp instance with 4x4 dots")
{
Testiconpp testicon(4, 4, Identiconpp::algorithm::sigil);
THEN("Required entropy is <= 16")
{
REQUIRE(testicon.test_check_entropy("ffff"));
}
}
WHEN("An Identiconpp instance with 255x255 dots")
{
Testiconpp testicon(255, 255, Identiconpp::algorithm::sigil);
THEN("Required entropy is <= 32644")
{
string digest(8162, 'c');
REQUIRE(testicon.test_check_entropy(digest));
}
}
}

110
tests/test_checks_hex.cpp Normal file
View File

@ -0,0 +1,110 @@
#include <catch.hpp>
#include <string>
#include <vector>
#include <exception>
#include "identiconpp.hpp"
using std::string;
class Testiconpp : private Identiconpp
{
public:
explicit Testiconpp()
: Identiconpp(1, 1) {};
bool test_check_not_hex(const char &c)
{
return not_hex(c);
}
};
SCENARIO("Hex checker check", "[checks][hex]")
{
GIVEN("Identiconpp instance")
{
Testiconpp testicon;
WHEN("digit is 0-9")
{
THEN("Return false")
{
for (char c = 0x30; c <= 0x39; ++c)
{
REQUIRE(testicon.test_check_not_hex(c) == false);
}
}
}
WHEN("digit is A-F")
{
THEN("Return false")
{
for (char c = 0x41; c <= 0x46; ++c)
{
REQUIRE(testicon.test_check_not_hex(c) == false);
}
}
}
WHEN("digit is a-f")
{
THEN("Return false")
{
for (char c = 0x61; c <= 0x66; ++c)
{
REQUIRE(testicon.test_check_not_hex(c) == false);
}
}
}
WHEN("digit is 0x00 - 0x29")
{
Testiconpp testicon;
THEN("Return true")
{
for (char c = 0x00; c <= 0x29; ++c)
{
REQUIRE(testicon.test_check_not_hex(c));
}
}
}
WHEN("digit is 0x3a - 0x40")
{
Testiconpp testicon;
THEN("Return true")
{
for (char c = 0x3a; c <= 0x40; ++c)
{
REQUIRE(testicon.test_check_not_hex(c));
}
}
}
WHEN("digit is 0x47 - 0x60")
{
Testiconpp testicon;
THEN("Return true")
{
for (char c = 0x47; c <= 0x60; ++c)
{
REQUIRE(testicon.test_check_not_hex(c));
}
}
}
WHEN("digit is 0x67 - 0x7f")
{
Testiconpp testicon;
THEN("Return true")
{
// We need to use an unsigned char to prevent overflowing
for (unsigned char c = 0x67; c <= 0x7f; ++c)
{
INFO("c=" << (int)c);
REQUIRE(testicon.test_check_not_hex(c));
}
}
}
}
}

272
tests/test_crash.cpp Normal file
View File

@ -0,0 +1,272 @@
#include <catch.hpp>
#include <string>
#include <exception>
#include <vector>
#include <Magick++/Image.h>
#include "identiconpp.hpp"
using std::string;
SCENARIO("Please do not crash")
{
GIVEN("The digest: sha256(test@example.com)")
{
string digest = "973dfe463ec85785f5f95af5ba3906ee"
"db2d931c24e69824a89ea65dba4e813b";
bool exception = false;
WHEN("256 bits of entropy is required")
{
try
{
Identiconpp identicon(18, 28,
Identiconpp::algorithm::ltr_symmetric,
"ffffffff",
{
"000000ff", "000000ff", "000000ff",
"000000ff", "000000ff", "000000ff",
"000000ff", "000000ff", "000000ff",
"000000ff", "000000ff", "000000ff",
"000000ff", "000000ff", "000000ff"
});
identicon.generate(digest);
}
catch (const std::exception &e)
{
exception = true;
}
THEN("Does not crash")
{
REQUIRE(exception == false);
}
}
WHEN("sigil is fed exactly 8 bit of colors")
{
try
{
std::vector<string> colors(256, "000000ff");
Identiconpp identicon(1, 1,
Identiconpp::algorithm::sigil,
"ffffffff", colors);
identicon.generate(digest);
}
catch (const std::exception &e)
{
exception = true;
}
THEN("Does not crash")
{
REQUIRE(exception == false);
}
}
WHEN("colors with uppercase hex digits")
{
try
{
Identiconpp identicon(1, 1, Identiconpp::algorithm::sigil,
"FF00FFFF");
identicon.generate(digest);
}
catch (const std::exception &e)
{
exception = true;
}
THEN("Does not crash")
{
REQUIRE(exception == false);
}
}
}
}
SCENARIO("Please crash")
{
GIVEN("The digest: sha256(test@example.com)")
{
string digest = "973dfe463ec85785f5f95af5ba3906ee"
"db2d931c24e69824a89ea65dba4e813b";
bool exception = false;
WHEN("257 bits of entropy is required")
{
try
{
Identiconpp identicon(18, 28,
Identiconpp::algorithm::ltr_symmetric,
"ffffffff",
{
"000000ff", "000000ff", "000000ff",
"000000ff", "000000ff", "000000ff",
"000000ff", "000000ff", "000000ff",
"000000ff", "000000ff", "000000ff",
"000000ff", "000000ff", "000000ff",
"000000ff"
});
identicon.generate(digest);
}
catch (const std::exception &e)
{
exception = true;
}
THEN("Crashes")
{
REQUIRE(exception == true);
}
}
WHEN("sigil is fed more than 8 bit of colors")
{
try
{
std::vector<string> colors(257, "000000ff");
Identiconpp identicon(1, 1,
Identiconpp::algorithm::sigil,
"ffffffff", colors);
identicon.generate(digest);
}
catch (const std::exception &e)
{
exception = true;
}
THEN("Crashes")
{
REQUIRE(exception == true);
}
}
WHEN("background color has too many digits")
{
try
{
Identiconpp identicon(1, 1,
Identiconpp::algorithm::ltr_symmetric,
"ffffffffa");
identicon.generate(digest);
}
catch (const std::exception &e)
{
exception = true;
}
THEN("Crashes")
{
REQUIRE(exception == true);
}
}
WHEN("background color has not enough digits")
{
try
{
Identiconpp identicon(1, 1,
Identiconpp::algorithm::ltr_symmetric,
"fffffff");
identicon.generate(digest);
}
catch (const std::exception &e)
{
exception = true;
}
THEN("Crashes")
{
REQUIRE(exception == true);
}
}
WHEN("Foreground color has too many digits")
{
try
{
Identiconpp identicon(1, 1,
Identiconpp::algorithm::ltr_symmetric,
"ffffffff", { "000000ffa"});
identicon.generate(digest);
}
catch (const std::exception &e)
{
exception = true;
}
THEN("Crashes")
{
REQUIRE(exception == true);
}
}
WHEN("Foreground color has not enough digits")
{
try
{
Identiconpp identicon(1, 1,
Identiconpp::algorithm::ltr_symmetric,
"ffffffff", { "000000f" });
identicon.generate(digest);
}
catch (const std::exception &e)
{
exception = true;
}
THEN("Crashes")
{
REQUIRE(exception == true);
}
}
WHEN("No foreground color")
{
try
{
Identiconpp identicon(1, 1,
Identiconpp::algorithm::ltr_symmetric,
"ffffffff", {});
identicon.generate(digest);
}
catch (const std::exception &e)
{
exception = true;
}
THEN("Crashes")
{
REQUIRE(exception == true);
}
}
WHEN("Non-hex digits in background color")
{
try
{
Identiconpp identicon(1, 1,
Identiconpp::algorithm::ltr_symmetric,
"ffffffgf");
identicon.generate(digest);
}
catch (const std::exception &e)
{
exception = true;
}
THEN("Crashes")
{
REQUIRE(exception == true);
}
}
WHEN("Non-hex digits in foreground color")
{
try
{
Identiconpp identicon(1, 1,
Identiconpp::algorithm::ltr_symmetric,
"ffffffff", { "g00000ff" });
identicon.generate(digest);
}
catch (const std::exception &e)
{
exception = true;
}
THEN("Crashes")
{
REQUIRE(exception == true);
}
}
}
}

View File

@ -0,0 +1,164 @@
#include <catch.hpp>
#include <string>
#include <Magick++/Image.h>
#include "identiconpp.hpp"
using std::string;
SCENARIO("ltr_asymmetric: Correct placement", "[ltr_asymmetric]")
{
GIVEN("An identiconpp instance with 2x2 dots")
{
Identiconpp identicon(2, 2, Identiconpp::algorithm::ltr_asymmetric);
Magick::Image img;
Magick::Color black("#000000ff");
Magick::Color white("#ffffffff");
WHEN("Digest is \"00\"")
{
img = identicon.generate("00", 2);
THEN("Is completely white")
{
REQUIRE(img.pixelColor(0, 0) == white);
REQUIRE(img.pixelColor(0, 1) == white);
REQUIRE(img.pixelColor(1, 0) == white);
REQUIRE(img.pixelColor(1, 1) == white);
}
}
WHEN("Digest is \"ff\"")
{
img = identicon.generate("ff", 2);
THEN("Is completely black")
{
REQUIRE(img.pixelColor(0, 0) == black);
REQUIRE(img.pixelColor(0, 1) == black);
REQUIRE(img.pixelColor(1, 0) == black);
REQUIRE(img.pixelColor(1, 1) == black);
}
}
WHEN("Digest is \"70\"")
{
// 0111 0000 = 01
// 11
img = identicon.generate("70", 2);
THEN("Produces white pixel at 0x0")
{
REQUIRE(img.pixelColor(0, 0) == white);
}
THEN("Produces black pixel at 1x0")
{
REQUIRE(img.pixelColor(1, 0) == black);
}
THEN("Produces black pixel at 1x0")
{
REQUIRE(img.pixelColor(0, 1) == black);
}
THEN("Produces black pixel at 1x1")
{
REQUIRE(img.pixelColor(1, 1) == black);
}
}
WHEN("Digest is \"80\"")
{
// 1000 0000 = 10
// 00
img = identicon.generate("80", 2);
THEN("Produces black pixel at 0x0")
{
REQUIRE(img.pixelColor(0, 0) == black);
}
THEN("Produces white pixel at 1x0")
{
REQUIRE(img.pixelColor(1, 0) == white);
}
THEN("Produces white pixel at 1x0")
{
REQUIRE(img.pixelColor(0, 1) == white);
}
THEN("Produces white pixel at 1x1")
{
REQUIRE(img.pixelColor(1, 1) == white);
}
}
}
}
SCENARIO("ltr_asymmetric: Correct color", "[ltr_asymmetric]")
{
GIVEN("An identiconpp instance with 5 foreground colors")
{
Identiconpp identicon(1, 1, Identiconpp::algorithm::ltr_asymmetric,
"ffffffff",
{
"ff0000ff",
"ffff00ff",
"00ff00ff",
"00ffffff",
"0000ffff"
});
Magick::Image img;
Magick::Color white("#ffffffff");
Magick::Color red("#ff0000ff");
Magick::Color yellow("#ffff00ff");
Magick::Color green("#00ff00ff");
Magick::Color cyan("#00ffffff");
Magick::Color blue("#0000ffff");
WHEN("Digest is \"0\"")
{ // 0000
img = identicon.generate("0", 1);
THEN("Is white")
{
REQUIRE(img.pixelColor(0, 0) == white);
}
}
WHEN("Digest is \"8\"")
{ // 1000
img = identicon.generate("8", 1);
THEN("Is red")
{
REQUIRE(img.pixelColor(0, 0) == red);
}
}
WHEN("Digest is \"9\"")
{ // 1001
img = identicon.generate("9", 1);
THEN("Is yellow")
{
REQUIRE(img.pixelColor(0, 0) == yellow);
}
}
WHEN("Digest is \"a\"")
{ // 1010
img = identicon.generate("a", 1);
THEN("Is green")
{
REQUIRE(img.pixelColor(0, 0) == green);
}
}
WHEN("Digest is \"b\"")
{ // 1011
img = identicon.generate("b", 1);
THEN("Is cyan")
{
REQUIRE(img.pixelColor(0, 0) == cyan);
}
}
WHEN("Digest is \"c\"")
{ // 1100
img = identicon.generate("c", 1);
THEN("Is blue")
{
REQUIRE(img.pixelColor(0, 0) == blue);
}
}
}
}

View File

@ -0,0 +1,164 @@
#include <catch.hpp>
#include <string>
#include <Magick++/Image.h>
#include "identiconpp.hpp"
using std::string;
SCENARIO("ltr_symmetric: Correct placement", "[ltr_symmetric]")
{
GIVEN("An identiconpp instance with 2x2 dots")
{
Identiconpp identicon(2, 2, Identiconpp::algorithm::ltr_symmetric);
Magick::Image img;
Magick::Color black("#000000ff");
Magick::Color white("#ffffffff");
WHEN("Digest is \"0\"")
{
img = identicon.generate("0", 2);
THEN("Is completely white")
{
REQUIRE(img.pixelColor(0, 0) == white);
REQUIRE(img.pixelColor(0, 1) == white);
REQUIRE(img.pixelColor(1, 0) == white);
REQUIRE(img.pixelColor(1, 1) == white);
}
}
WHEN("Digest is \"f\"")
{
img = identicon.generate("f", 2);
THEN("Is completely black")
{
REQUIRE(img.pixelColor(0, 0) == black);
REQUIRE(img.pixelColor(0, 1) == black);
REQUIRE(img.pixelColor(1, 0) == black);
REQUIRE(img.pixelColor(1, 1) == black);
}
}
WHEN("Digest is \"7\"")
{
// 0111 = 00
// 11
img = identicon.generate("7", 2);
THEN("Produces white pixel at 0x0")
{
REQUIRE(img.pixelColor(0, 0) == white);
}
THEN("Produces white pixel at 1x0")
{
REQUIRE(img.pixelColor(1, 0) == white);
}
THEN("Produces black pixel at 1x0")
{
REQUIRE(img.pixelColor(0, 1) == black);
}
THEN("Produces black pixel at 1x1")
{
REQUIRE(img.pixelColor(1, 1) == black);
}
}
WHEN("Digest is \"8\"")
{
// 1000 = 11
// 00
img = identicon.generate("8", 2);
THEN("Produces black pixel at 0x0")
{
REQUIRE(img.pixelColor(0, 0) == black);
}
THEN("Produces black pixel at 1x0")
{
REQUIRE(img.pixelColor(1, 0) == black);
}
THEN("Produces white pixel at 1x0")
{
REQUIRE(img.pixelColor(0, 1) == white);
}
THEN("Produces white pixel at 1x1")
{
REQUIRE(img.pixelColor(1, 1) == white);
}
}
}
}
SCENARIO("ltr_symmetric: Correct color", "[ltr_symmetric]")
{
GIVEN("An identiconpp instance with 5 foreground colors")
{
Identiconpp identicon(1, 1, Identiconpp::algorithm::ltr_symmetric,
"ffffffff",
{
"ff0000ff",
"ffff00ff",
"00ff00ff",
"00ffffff",
"0000ffff"
});
Magick::Image img;
Magick::Color white("#ffffffff");
Magick::Color red("#ff0000ff");
Magick::Color yellow("#ffff00ff");
Magick::Color green("#00ff00ff");
Magick::Color cyan("#00ffffff");
Magick::Color blue("#0000ffff");
WHEN("Digest is \"0\"")
{ // 0000
img = identicon.generate("0", 1);
THEN("Is white")
{
REQUIRE(img.pixelColor(0, 0) == white);
}
}
WHEN("Digest is \"8\"")
{ // 1000
img = identicon.generate("8", 1);
THEN("Is red")
{
REQUIRE(img.pixelColor(0, 0) == red);
}
}
WHEN("Digest is \"9\"")
{ // 1001
img = identicon.generate("9", 1);
THEN("Is yellow")
{
REQUIRE(img.pixelColor(0, 0) == yellow);
}
}
WHEN("Digest is \"a\"")
{ // 1010
img = identicon.generate("a", 1);
THEN("Is green")
{
REQUIRE(img.pixelColor(0, 0) == green);
}
}
WHEN("Digest is \"b\"")
{ // 1011
img = identicon.generate("b", 1);
THEN("Is cyan")
{
REQUIRE(img.pixelColor(0, 0) == cyan);
}
}
WHEN("Digest is \"c\"")
{ // 1100
img = identicon.generate("c", 1);
THEN("Is blue")
{
REQUIRE(img.pixelColor(0, 0) == blue);
}
}
}
}

164
tests/test_sigil.cpp Normal file
View File

@ -0,0 +1,164 @@
#include <catch.hpp>
#include <string>
#include <Magick++/Image.h>
#include "identiconpp.hpp"
using std::string;
SCENARIO("sigil: Correct placement", "[sigil]")
{
GIVEN("An identiconpp instance with 2x2 dots")
{
Identiconpp identicon(2, 2, Identiconpp::algorithm::sigil);
Magick::Image img;
Magick::Color black("#000000ff");
Magick::Color white("#ffffffff");
WHEN("Digest is \"000\"")
{
img = identicon.generate("000", 2);
THEN("Is completely white")
{
REQUIRE(img.pixelColor(0, 0) == white);
REQUIRE(img.pixelColor(0, 1) == white);
REQUIRE(img.pixelColor(1, 0) == white);
REQUIRE(img.pixelColor(1, 1) == white);
}
}
WHEN("Digest is \"fff\"")
{
img = identicon.generate("fff", 2);
THEN("Is completely black")
{
REQUIRE(img.pixelColor(0, 0) == black);
REQUIRE(img.pixelColor(0, 1) == black);
REQUIRE(img.pixelColor(1, 0) == black);
REQUIRE(img.pixelColor(1, 1) == black);
}
}
WHEN("Digest is \"007\"")
{
// 0000 0000 0111 = 00
// 11
img = identicon.generate("007", 2);
THEN("Produces white pixel at 0x0")
{
REQUIRE(img.pixelColor(0, 0) == white);
}
THEN("Produces white pixel at 1x0")
{
REQUIRE(img.pixelColor(1, 0) == white);
}
THEN("Produces black pixel at 1x0")
{
REQUIRE(img.pixelColor(0, 1) == black);
}
THEN("Produces black pixel at 1x1")
{
REQUIRE(img.pixelColor(1, 1) == black);
}
}
WHEN("Digest is \"008\"")
{
// 0000 0000 1000 = 11
// 00
img = identicon.generate("008", 2);
THEN("Produces black pixel at 0x0")
{
REQUIRE(img.pixelColor(0, 0) == black);
}
THEN("Produces black pixel at 1x0")
{
REQUIRE(img.pixelColor(1, 0) == black);
}
THEN("Produces white pixel at 1x0")
{
REQUIRE(img.pixelColor(0, 1) == white);
}
THEN("Produces white pixel at 1x1")
{
REQUIRE(img.pixelColor(1, 1) == white);
}
}
}
}
SCENARIO("sigil: Correct color", "[sigil]")
{
GIVEN("An identiconpp instance with 5 foreground colors")
{
Identiconpp identicon(1, 1, Identiconpp::algorithm::sigil,
"ffffffff",
{
"ff0000ff",
"ffff00ff",
"00ff00ff",
"00ffffff",
"0000ffff"
});
Magick::Image img;
Magick::Color white("#ffffffff");
Magick::Color red("#ff0000ff");
Magick::Color yellow("#ffff00ff");
Magick::Color green("#00ff00ff");
Magick::Color cyan("#00ffffff");
Magick::Color blue("#0000ffff");
WHEN("Digest is \"000\"")
{ // 0000 0000 0000
img = identicon.generate("000", 1);
THEN("Is white")
{
REQUIRE(img.pixelColor(0, 0) == white);
}
}
WHEN("Digest is \"008\"")
{ // 0000 0000 1000
img = identicon.generate("008", 1);
THEN("Is red")
{
REQUIRE(img.pixelColor(0, 0) == red);
}
}
WHEN("Digest is \"108\"")
{ // 0001 0000 1000
img = identicon.generate("108", 1);
THEN("Is yellow")
{
REQUIRE(img.pixelColor(0, 0) == yellow);
}
}
WHEN("Digest is \"208\"")
{ // 0010 0000 1000
img = identicon.generate("208", 1);
THEN("Is green")
{
REQUIRE(img.pixelColor(0, 0) == green);
}
}
WHEN("Digest is \"308\"")
{ // 0011 0000 1000
img = identicon.generate("308", 1);
THEN("Is cyan")
{
REQUIRE(img.pixelColor(0, 0) == cyan);
}
}
WHEN("Digest is \"408\"")
{ // 0100 0000 1000
img = identicon.generate("408", 1);
THEN("Is blue")
{
REQUIRE(img.pixelColor(0, 0) == blue);
}
}
}
}