├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.markdown ├── misc └── examples │ ├── 1369.png │ ├── 31512-factor-1.png │ ├── 31512-factor-4.png │ ├── Foobar.png │ └── ahf.png └── src ├── bin └── hashvis.rs └── hashvis ├── expression ├── cos_pi.rs ├── elliptic_curve.rs ├── mod.rs ├── product.rs ├── sin_pi.rs ├── tan_pi.rs ├── x.rs └── y.rs ├── lib.rs └── math └── mod.rs /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.rs.bk 2 | /target/ 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | 3 | rust: 4 | - stable 5 | - beta 6 | - nightly 7 | 8 | matrix: 9 | allow_failures: 10 | - rust: nightly 11 | 12 | cache: cargo 13 | 14 | before_script: 15 | - rustup component add rustfmt-preview 16 | script: 17 | - cargo fmt --all -- --check 18 | - cargo build 19 | - cargo test 20 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hashvis" 3 | version = "0.1.0" 4 | description = "Visualize hashed values as images." 5 | authors = ["Alexander Færøy "] 6 | repository = "https://github.com/ahf/hashvis" 7 | license = "BSD-2-Clause" 8 | readme = "README.markdown" 9 | 10 | [badges] 11 | travis-ci = { repository = "ahf/hashvis", branch = "master" } 12 | 13 | [lib] 14 | name = "hashvis" 15 | path = "src/hashvis/lib.rs" 16 | 17 | [dependencies] 18 | image = "*" 19 | rand = "0.4" 20 | sha3 = "0.7.2" 21 | clap = "2.30.0" 22 | 23 | [[bin]] 24 | name = "hashvis" 25 | test = false 26 | doc = false 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Alexander Færøy. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Hashvis [![Build Status](https://travis-ci.org/ahf/hashvis.svg?branch=master)](https://travis-ci.org/ahf/hashvis) 2 | 3 | **A Rust application for deterministic generation of images.** 4 | 5 | Hashvis is a small Rust application and library for generating very psychedelic 6 | images from an input string. The images are generated in a deterministic manner 7 | such that the same input string should always result in the same image being 8 | generated. 9 | 10 | Hashvis is inspired by OpenSSH's `VisualHostKey` where the OpenSSH client will 11 | display a deterministic piece of ASCII art generated from the host keys when 12 | you are trying to authenticate with a remote server. The idea behind this 13 | feature is that humans have an easier way to remember visual impressions than 14 | long, hex-encoded, fingerprints. 15 | 16 | Example usage could be: 17 | 18 | - OpenSSH host keys (like with `VisualHostKey` described above). 19 | - OpenPGP public key fingerprints. 20 | - Tor onion and next-generation onion public keys. 21 | 22 | Currently Hashvis takes the user input string and passes it to the SHA3-256 23 | hash function and uses this hash value to seed the ChaCha random number 24 | generator. The random number generator is then used to generate a lot of 64-bit 25 | floating-point values that are used to generate the expressions that is finally 26 | used to plot the RGB image. 27 | 28 | ## Building Hashvis 29 | 30 | To download and build Hashvis: 31 | 32 | $ git clone https://github.com/ahf/hashvis.git 33 | $ cd hashvis 34 | $ cargo build 35 | 36 | You can try running the application using: 37 | 38 | $ cargo run --bin hashvis misc/examples/yourusername.png yourusername 256 39 | Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs 40 | Running `target/debug/hashvis misc/examples/yourusername.png yourusername` 41 | Generating image with SHA3("yourusername") in misc/examples/yourusername.png ... 42 | R: f(x, y) = cos(pi * sin(pi * cos(pi * tan(pi * sin(pi * sin(pi * y) * y)) * y))) 43 | G: f(x, y) = tan(pi * tan(pi * cos(pi * x * tan(pi * y) * x * x)) * tan(pi * sin(pi * sin(pi * x) * sin(pi * y)))) 44 | B: f(x, y) = tan(pi * x) 45 | 46 | Feel free to submit a pull request if you think your generated image looks 47 | spectacular. 48 | 49 | ## Testing Hashvis 50 | 51 | To run the minimal test suite: 52 | 53 | $ cargo test 54 | 55 | ## Zooming In and Out 56 | 57 | The `factor` argument that the Hashvis binary takes as an input allows you to 58 | zoom in and out. A value smaller than 1.0 will zoom in, and anything larger 59 | than 1.0 will zoom out of the normal view port. The default value is 1.0. 60 | 61 | ![31512-1](https://raw.githubusercontent.com/ahf/hashvis/master/misc/examples/31512-factor-1.png "SHA3(31512) with factor = 1 (default)") 62 | ![31512-4](https://raw.githubusercontent.com/ahf/hashvis/master/misc/examples/31512-factor-4.png "SHA3(31512) with factor = 4") 63 | 64 | ## Authors 65 | 66 | - Alexander Færøy (). 67 | 68 | ## Interactive Twitter Bot 69 | 70 | Matthew Garrett (@mjg59) wrote a very cool interactive Twitter bot which 71 | fetches your Github SSH Public Key and executes Hashvis on the first key and 72 | tweets out the generated picture. 73 | 74 | You can write your Github username to the bot and it will tweet out your, 75 | hopefully very unique, picture. 76 | 77 | Check out the bot at https://twitter.com/github_idbot 78 | 79 | ## Gallery 80 | 81 | ![ahf](https://raw.githubusercontent.com/ahf/hashvis/master/misc/examples/ahf.png "SHA3(ahf)") 82 | ![Foobar](https://raw.githubusercontent.com/ahf/hashvis/master/misc/examples/Foobar.png "SHA3(Foobar)") 83 | ![1369](https://raw.githubusercontent.com/ahf/hashvis/master/misc/examples/1369.png "SHA3(1369)") 84 | -------------------------------------------------------------------------------- /misc/examples/1369.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahf/hashvis/25d8f95ec4ff5e8c486d6db8fcf4899820e2a5c9/misc/examples/1369.png -------------------------------------------------------------------------------- /misc/examples/31512-factor-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahf/hashvis/25d8f95ec4ff5e8c486d6db8fcf4899820e2a5c9/misc/examples/31512-factor-1.png -------------------------------------------------------------------------------- /misc/examples/31512-factor-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahf/hashvis/25d8f95ec4ff5e8c486d6db8fcf4899820e2a5c9/misc/examples/31512-factor-4.png -------------------------------------------------------------------------------- /misc/examples/Foobar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahf/hashvis/25d8f95ec4ff5e8c486d6db8fcf4899820e2a5c9/misc/examples/Foobar.png -------------------------------------------------------------------------------- /misc/examples/ahf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahf/hashvis/25d8f95ec4ff5e8c486d6db8fcf4899820e2a5c9/misc/examples/ahf.png -------------------------------------------------------------------------------- /src/bin/hashvis.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | extern crate clap; 6 | extern crate sha3; 7 | 8 | extern crate hashvis; 9 | 10 | use clap::{App, Arg}; 11 | use sha3::{Digest, Sha3_256}; 12 | 13 | use hashvis::ImageGenerator; 14 | 15 | fn main() { 16 | let matches = App::new("hashvis") 17 | .version("0.1.0") 18 | .author("Alexander Færøy ") 19 | .about("Visualize hash values") 20 | .arg(Arg::with_name("filename") 21 | .required(true) 22 | .takes_value(true) 23 | .index(1) 24 | .help("Output file to store the image in. The extension of the filename decides the image output format.")) 25 | .arg(Arg::with_name("string") 26 | .required(true) 27 | .takes_value(true) 28 | .index(2) 29 | .help("Input string to hash with SHA3-256.")) 30 | .arg(Arg::with_name("size") 31 | .required(true) 32 | .takes_value(true) 33 | .index(3) 34 | .help("Size of the output image")) 35 | .arg(Arg::with_name("factor") 36 | .required(false) 37 | .takes_value(true) 38 | .index(4) 39 | .help("Factor specifies how much to zoom out on the image.")) 40 | .get_matches(); 41 | 42 | let filename = matches.value_of("filename").unwrap(); 43 | let string = matches.value_of("string").unwrap(); 44 | let size = matches.value_of("size").unwrap(); 45 | let factor = matches.value_of("factor").unwrap_or("1.0"); 46 | 47 | println!( 48 | "Generating image with SHA3(\"{}\") in {} ...", 49 | string, filename 50 | ); 51 | 52 | let mut h = Sha3_256::default(); 53 | h.input(string.as_bytes()); 54 | let r = h.result(); 55 | 56 | let generator = ImageGenerator::new(r.as_slice()); 57 | generator.generate( 58 | String::from(filename), 59 | size.parse().unwrap_or(256), 60 | factor.parse().unwrap_or(1.0), 61 | ); 62 | } 63 | -------------------------------------------------------------------------------- /src/hashvis/expression/cos_pi.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | use std::fmt; 6 | 7 | use expression::{Evaluate, Generator}; 8 | use math::{cos, PI}; 9 | 10 | pub struct CosPi { 11 | expression: Box, 12 | } 13 | 14 | impl CosPi { 15 | pub fn new(expression: Box) -> CosPi { 16 | CosPi { expression } 17 | } 18 | 19 | pub fn generate(generator: &mut Generator, probability: f64) -> Box { 20 | let expression = generator.generate_expression(probability * probability); 21 | 22 | Box::new(CosPi::new(expression)) 23 | } 24 | } 25 | 26 | impl Evaluate for CosPi { 27 | fn evaluate(&self, x: f64, y: f64) -> f64 { 28 | cos(PI * self.expression.evaluate(x, y)) 29 | } 30 | } 31 | 32 | impl fmt::Display for CosPi { 33 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 34 | write!(f, "cos(pi * {})", self.expression) 35 | } 36 | } 37 | 38 | #[cfg(test)] 39 | mod tests { 40 | use super::*; 41 | use expression::{X, Y}; 42 | 43 | #[test] 44 | fn format() { 45 | assert_eq!("cos(pi * x)", format!("{}", CosPi::new(X::generate()))); 46 | assert_eq!("cos(pi * y)", format!("{}", CosPi::new(Y::generate()))); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/hashvis/expression/elliptic_curve.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | use std::fmt; 6 | 7 | use expression::{Evaluate, Generator}; 8 | 9 | pub struct EllipticCurve { 10 | a: f64, 11 | b: f64, 12 | } 13 | 14 | impl EllipticCurve { 15 | pub fn new(a: f64, b: f64) -> EllipticCurve { 16 | EllipticCurve { a, b } 17 | } 18 | 19 | pub fn generate(generator: &mut Generator) -> Box { 20 | let a = generator.next_f64(); 21 | let b = generator.next_f64(); 22 | 23 | Box::new(EllipticCurve::new(a, b)) 24 | } 25 | } 26 | 27 | impl Evaluate for EllipticCurve { 28 | fn evaluate(&self, x: f64, y: f64) -> f64 { 29 | x.powf(3.0) + self.a * x + self.b - y.powf(2.0) 30 | } 31 | } 32 | 33 | impl fmt::Display for EllipticCurve { 34 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 35 | write!(f, "EllipticCurve(x^3 + {} * x + {} - y^2)", self.a, self.b) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/hashvis/expression/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | use std::fmt; 6 | use std::mem; 7 | 8 | use rand::chacha::ChaChaRng; 9 | use rand::{Rng, SeedableRng}; 10 | 11 | mod x; 12 | use self::x::X; 13 | 14 | mod y; 15 | use self::y::Y; 16 | 17 | mod product; 18 | use self::product::Product; 19 | 20 | mod sin_pi; 21 | use self::sin_pi::SinPi; 22 | 23 | mod cos_pi; 24 | use self::cos_pi::CosPi; 25 | 26 | mod tan_pi; 27 | use self::tan_pi::TanPi; 28 | 29 | mod elliptic_curve; 30 | use self::elliptic_curve::EllipticCurve; 31 | 32 | pub enum ExpressionType { 33 | SinPi, 34 | CosPi, 35 | TanPi, 36 | Product, 37 | EllipticCurve, 38 | X, 39 | Y, 40 | } 41 | 42 | impl ExpressionType { 43 | pub fn generate(&self, generator: &mut Generator, probability: f64) -> Box { 44 | match *self { 45 | ExpressionType::SinPi => SinPi::generate(generator, probability), 46 | ExpressionType::CosPi => CosPi::generate(generator, probability), 47 | ExpressionType::TanPi => TanPi::generate(generator, probability), 48 | ExpressionType::Product => Product::generate(generator, probability), 49 | ExpressionType::EllipticCurve => EllipticCurve::generate(generator), 50 | ExpressionType::X => X::generate(), 51 | ExpressionType::Y => Y::generate(), 52 | } 53 | } 54 | } 55 | 56 | /// Trait for items that supports evaluating expressions at a given 57 | /// point in a Cartesian coordinate system. 58 | pub trait Evaluate: fmt::Display { 59 | /// Returns the z value at the given x and y coordinate. 60 | /// 61 | /// # Arguments 62 | /// 63 | /// * `x` - The x coordinate. 64 | /// * `y` - The y coordinate. 65 | /// 66 | fn evaluate(&self, x: f64, y: f64) -> f64; 67 | } 68 | 69 | pub struct Generator { 70 | rng: Box, 71 | random_data_used: usize, 72 | } 73 | 74 | impl Generator { 75 | pub fn new(seed: &[u8]) -> Generator { 76 | // FIXME(ahf): This could probably done in a nicer way. The 77 | // ChaChaRng::from_seed() takes a [u32; 32], but uses it 78 | // internally as an [u8; 32]. We therefore have to do the safe 79 | // conversion from [u8; 32] to [u32; 32] ourselves. This appears 80 | // to be fixed in the Rand Github repository. 81 | let mut v: Vec = Vec::with_capacity(32); 82 | 83 | for value in seed.iter() { 84 | v.push(*value as u32); 85 | } 86 | 87 | Generator { 88 | rng: Box::new(ChaChaRng::from_seed(v.as_slice())), 89 | random_data_used: 0, 90 | } 91 | } 92 | 93 | pub fn random_data_used(self) -> usize { 94 | self.random_data_used 95 | } 96 | 97 | pub fn next_f64(&mut self) -> f64 { 98 | self.random_data_used += mem::size_of::(); 99 | self.rng.next_f64() 100 | } 101 | 102 | pub fn generate(&mut self) -> Box { 103 | self.generate_expression(0.99) 104 | } 105 | 106 | pub fn generate_expression(&mut self, probability: f64) -> Box { 107 | assert!(probability >= 0.00 && probability < 1.00); 108 | 109 | let mut set = Vec::new(); 110 | 111 | if self.next_f64() < probability { 112 | set.push(ExpressionType::SinPi); 113 | set.push(ExpressionType::CosPi); 114 | set.push(ExpressionType::TanPi); 115 | set.push(ExpressionType::Product); 116 | set.push(ExpressionType::EllipticCurve); 117 | } else { 118 | set.push(ExpressionType::X); 119 | set.push(ExpressionType::Y); 120 | } 121 | 122 | self.rng.shuffle(&mut set); 123 | let expression_type = set.remove(0); 124 | expression_type.generate(self, probability) 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/hashvis/expression/product.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | use std::fmt; 6 | 7 | use expression::{Evaluate, Generator}; 8 | 9 | pub struct Product { 10 | expression_lhs: Box, 11 | expression_rhs: Box, 12 | } 13 | 14 | impl Product { 15 | pub fn new(expression_lhs: Box, expression_rhs: Box) -> Product { 16 | Product { 17 | expression_lhs, 18 | expression_rhs, 19 | } 20 | } 21 | 22 | pub fn generate(generator: &mut Generator, probability: f64) -> Box { 23 | let lhs = generator.generate_expression(probability * probability); 24 | let rhs = generator.generate_expression(probability * probability); 25 | 26 | Box::new(Product::new(lhs, rhs)) 27 | } 28 | } 29 | 30 | impl Evaluate for Product { 31 | fn evaluate(&self, x: f64, y: f64) -> f64 { 32 | self.expression_lhs.evaluate(x, y) * self.expression_rhs.evaluate(x, y) 33 | } 34 | } 35 | 36 | impl fmt::Display for Product { 37 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 38 | write!(f, "{} * {}", self.expression_lhs, self.expression_rhs) 39 | } 40 | } 41 | 42 | #[cfg(test)] 43 | mod tests { 44 | use super::*; 45 | use expression::{X, Y}; 46 | 47 | #[test] 48 | fn format() { 49 | assert_eq!( 50 | "x * y", 51 | format!("{}", Product::new(Box::new(X::new()), Box::new(Y::new()))) 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/hashvis/expression/sin_pi.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | use std::fmt; 6 | 7 | use expression::{Evaluate, Generator}; 8 | use math::{sin, PI}; 9 | 10 | pub struct SinPi { 11 | expression: Box, 12 | } 13 | 14 | impl SinPi { 15 | pub fn new(expression: Box) -> SinPi { 16 | SinPi { expression } 17 | } 18 | 19 | pub fn generate(generator: &mut Generator, probability: f64) -> Box { 20 | let expression = generator.generate_expression(probability * probability); 21 | 22 | Box::new(SinPi::new(expression)) 23 | } 24 | } 25 | 26 | impl Evaluate for SinPi { 27 | fn evaluate(&self, x: f64, y: f64) -> f64 { 28 | sin(PI * self.expression.evaluate(x, y)) 29 | } 30 | } 31 | 32 | impl fmt::Display for SinPi { 33 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 34 | write!(f, "sin(pi * {})", self.expression) 35 | } 36 | } 37 | 38 | #[cfg(test)] 39 | mod tests { 40 | use super::*; 41 | use expression::{X, Y}; 42 | 43 | #[test] 44 | fn format() { 45 | assert_eq!("sin(pi * x)", format!("{}", SinPi::new(X::generate()))); 46 | assert_eq!("sin(pi * y)", format!("{}", SinPi::new(Y::generate()))); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/hashvis/expression/tan_pi.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | use std::fmt; 6 | 7 | use expression::{Evaluate, Generator}; 8 | use math::{tan, PI}; 9 | 10 | pub struct TanPi { 11 | expression: Box, 12 | } 13 | 14 | impl TanPi { 15 | pub fn new(expression: Box) -> TanPi { 16 | TanPi { expression } 17 | } 18 | 19 | pub fn generate(generator: &mut Generator, probability: f64) -> Box { 20 | let expression = generator.generate_expression(probability * probability); 21 | 22 | Box::new(TanPi::new(expression)) 23 | } 24 | } 25 | 26 | impl Evaluate for TanPi { 27 | fn evaluate(&self, x: f64, y: f64) -> f64 { 28 | tan(PI * self.expression.evaluate(x, y)) 29 | } 30 | } 31 | 32 | impl fmt::Display for TanPi { 33 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 34 | write!(f, "tan(pi * {})", self.expression) 35 | } 36 | } 37 | 38 | #[cfg(test)] 39 | mod tests { 40 | use super::*; 41 | use expression::{X, Y}; 42 | 43 | #[test] 44 | fn format() { 45 | assert_eq!("tan(pi * x)", format!("{}", TanPi::new(X::generate()))); 46 | assert_eq!("tan(pi * y)", format!("{}", TanPi::new(Y::generate()))); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/hashvis/expression/x.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | use std::fmt; 6 | 7 | use expression::Evaluate; 8 | 9 | /// The X coordinate in the Cartesian coordinate system. 10 | pub struct X; 11 | 12 | impl X { 13 | pub fn new() -> X { 14 | X {} 15 | } 16 | 17 | pub fn generate() -> Box { 18 | Box::new(X::new()) 19 | } 20 | } 21 | 22 | impl Evaluate for X { 23 | fn evaluate(&self, x: f64, _y: f64) -> f64 { 24 | x 25 | } 26 | } 27 | 28 | impl fmt::Display for X { 29 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 30 | write!(f, "x") 31 | } 32 | } 33 | 34 | #[cfg(test)] 35 | mod tests { 36 | use super::*; 37 | 38 | #[test] 39 | fn format() { 40 | assert_eq!("x", format!("{}", X::new())); 41 | } 42 | 43 | #[test] 44 | fn evaluate() { 45 | let x = X::new(); 46 | assert_eq!(x.evaluate(-1.0, 1.0), -1.0); 47 | assert_eq!(x.evaluate(1.0, -1.0), 1.0); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/hashvis/expression/y.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | use std::fmt; 6 | 7 | use expression::Evaluate; 8 | 9 | /// The Y coordinate in the Cartesian coordinate system. 10 | pub struct Y; 11 | 12 | impl Y { 13 | pub fn new() -> Y { 14 | Y {} 15 | } 16 | 17 | pub fn generate() -> Box { 18 | Box::new(Y::new()) 19 | } 20 | } 21 | 22 | impl Evaluate for Y { 23 | fn evaluate(&self, _x: f64, y: f64) -> f64 { 24 | y 25 | } 26 | } 27 | 28 | impl fmt::Display for Y { 29 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 30 | write!(f, "y") 31 | } 32 | } 33 | 34 | #[cfg(test)] 35 | mod tests { 36 | use super::*; 37 | 38 | #[test] 39 | fn format() { 40 | assert_eq!("y", format!("{}", Y::new())); 41 | } 42 | 43 | #[test] 44 | fn evaluate() { 45 | let y = Y::new(); 46 | assert_eq!(y.evaluate(-1.0, 1.0), 1.0); 47 | assert_eq!(y.evaluate(1.0, -1.0), -1.0); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/hashvis/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | extern crate image; 6 | extern crate rand; 7 | 8 | use image::{Rgb, RgbImage}; 9 | 10 | /// Expression types and helpers. 11 | mod expression; 12 | use self::expression::{Evaluate, Generator}; 13 | 14 | /// Various math helpers. 15 | mod math; 16 | 17 | fn to_u8(x: f64) -> u8 { 18 | (x * 127.5 + 127.5) as u8 19 | } 20 | 21 | pub struct ImageGenerator { 22 | r: Box, 23 | g: Box, 24 | b: Box, 25 | random_data_used: usize, 26 | } 27 | 28 | impl ImageGenerator { 29 | pub fn new(seed: &[u8]) -> ImageGenerator { 30 | let mut generator = Generator::new(seed); 31 | 32 | ImageGenerator { 33 | r: generator.generate(), 34 | g: generator.generate(), 35 | b: generator.generate(), 36 | random_data_used: generator.random_data_used(), 37 | } 38 | } 39 | 40 | pub fn generate(&self, filename: String, size: u32, factor: f64) { 41 | let unit_size: f64 = (size as f64) / 2.0; 42 | 43 | assert!(size % 2 == 0); 44 | 45 | println!("R: f(x, y) = {}", self.r); 46 | println!("G: f(x, y) = {}", self.g); 47 | println!("B: f(x, y) = {}", self.b); 48 | 49 | println!("Random data used = {}", self.random_data_used); 50 | 51 | let image = RgbImage::from_fn(size, size, |i_x, i_y| { 52 | let x = (((i_x as f64) - unit_size) / unit_size) * factor; 53 | let y = (((i_y as f64) - unit_size) / unit_size) * factor; 54 | 55 | let r = self.r.evaluate(x, y); 56 | let g = self.g.evaluate(x, y); 57 | let b = self.b.evaluate(x, y); 58 | 59 | Rgb([to_u8(r), to_u8(g), to_u8(b)]) 60 | }); 61 | 62 | image.save(filename).unwrap(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/hashvis/math/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Alexander Færøy. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | use std::f64; 6 | 7 | /// Alias for the std::f64::consts::PI. 8 | pub const PI: f64 = f64::consts::PI; 9 | 10 | /// Returns the sine of the value in, radians. 11 | pub fn sin(value: f64) -> f64 { 12 | value.sin() 13 | } 14 | 15 | /// Returns the cosine of the value, in radians. 16 | pub fn cos(value: f64) -> f64 { 17 | value.cos() 18 | } 19 | 20 | /// Returns the tangent of the value, in radians. 21 | pub fn tan(value: f64) -> f64 { 22 | value.tan() 23 | } 24 | --------------------------------------------------------------------------------