jazzicon 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1c28a74ab282c10c0caea691c048f7bc5598ee0cc92a867950b8bd20176cd4e2
4
+ data.tar.gz: befd3d81c9bbed1bfcecac4bc6d911761f053814eb2066d27ce8904b13c36444
5
+ SHA512:
6
+ metadata.gz: 7c5d2eef67d11f3284e34f567ea236510fca7f746f9e4281a645aa7b6121bc9436a78a777401bcdbf08a0d0f140512497423c588184f8d147e44692db3f1e723
7
+ data.tar.gz: 892a0e2f7a0d3ec3a14208f1df3f283392a0e419a7f0e3c8cbfd0c556fdf3dbfe4e5cbe8b434ab8298309204313bb26e2c3566f310653b8e13028c03d64c011d
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Arux Software, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # Jazzicon
2
+
3
+ This is a ruby port of https://github.com/danfinlay/jazzicon
4
+
5
+ > Say goodbye to boring blocky identicons that look like they came out of the 70s, and replace them with jazzy, colorful collages that more likely came out of the 80's.
6
+
7
+ ![Example](https://github.com/Arux-Software/jazzicon_ruby/examples.png?raw=true)
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'jazzicon'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle install
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install jazzicon
24
+
25
+ ## Usage
26
+
27
+ ```ruby
28
+ require 'jazzicon'
29
+ Jazzicon::Icon.generate("random string or integer").save("icon.png")
30
+ ```
31
+
32
+ ## Development
33
+
34
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
35
+
36
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
37
+
38
+ ## Contributing
39
+
40
+ Bug reports and pull requests are welcome on GitHub at https://github.com/Arux-Software/jazzicon_ruby.
41
+
42
+ ## License
43
+
44
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jazzicon
4
+ HUE_WOBBLE = 30
5
+ # The Jazzicon::ColorHelpers module provides color-related helper methods.
6
+ module ColorHelpers
7
+ # Shifts the hue of the given colors by a random amount.
8
+ #
9
+ # @param colors [Array<String>] Array of hex color strings.
10
+ # @param random [Random] Random object for deterministic randomness.
11
+ # @return [Array<String>] Array of hue-shifted colors.
12
+ def self.hue_shift(colors, random)
13
+ amount = (random.rand * 30) - (HUE_WOBBLE / 2.0)
14
+
15
+ colors.map do |hex|
16
+ hsl = ChunkyPNG::Color.to_hsl(ChunkyPNG::Color.from_hex(hex))
17
+ hsl[0] = (hsl[0] + amount) % 360
18
+ hsl[3] = 255
19
+ ChunkyPNG::Color.from_hsl(*hsl)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jazzicon
4
+ Rectangle = Struct.new(:corners, keyword_init: true)
5
+ Point = Struct.new(:x, :y, keyword_init: true)
6
+ Size = Struct.new(:width, :height, keyword_init: true)
7
+
8
+ # The Jazzicon::GeometryHelpers module provides methods for geometric calculations and operations.
9
+ module GeometryHelpers
10
+ # Adds a randomly positioned and rotated rectangle to the given image.
11
+ #
12
+ # @param image [ChunkyPNG::Image] The image to modify.
13
+ # @param diameter [Integer] The diameter of the image.
14
+ # @param color [String] The color of the rectangle.
15
+ # @param index [Integer] The index of the current shape.
16
+ # @param total [Integer] The total number of shapes.
17
+ # @param random_numbers [Array<Float>] Array of random numbers for positioning and rotation.
18
+ def self.random_rectangle(diameter, index, total, random_numbers)
19
+ velocity, rotation, angle = generate_momentum(diameter, index, total, random_numbers)
20
+ center = diameter / 2.0
21
+
22
+ point = Point.new(
23
+ x: center + (Math.cos(angle) * velocity),
24
+ y: center + (Math.sin(angle) * velocity)
25
+ )
26
+ size = Size.new(width: diameter, height: diameter)
27
+
28
+ # Draw the rectangle
29
+ rotated_rectangle(point, size, rotation, center)
30
+ end
31
+
32
+ private_class_method def self.generate_momentum(diameter, index, total, random_numbers)
33
+ first_rot = random_numbers.pop
34
+ velocity = (diameter / total * random_numbers.pop) + (index * diameter / total)
35
+ rotation = (first_rot * 360) + (random_numbers.pop * 180)
36
+ angle = Math::PI * 2 * first_rot
37
+
38
+ [velocity, rotation, angle]
39
+ end
40
+
41
+ # Draws a rotated rectangle on the image.
42
+ #
43
+ # @param image [ChunkyPNG::Image] The image to modify.
44
+ # @param x [Float] The x-coordinate of the rectangle's center.
45
+ # @param y [Float] The y-coordinate of the rectangle's center.
46
+ # @param width [Float] The width of the rectangle.
47
+ # @param height [Float] The height of the rectangle.
48
+ # @param color [String] The color of the rectangle.
49
+ # @param rotation [Float] The rotation angle in degrees.
50
+ # @param center [Float] The center point of the image.
51
+ def self.rotated_rectangle(point, size, rotation, center)
52
+ # Define the four corners of the rectangle
53
+ corners = rotate_corners(calculate_corners(point, size), rotation, center)
54
+ Rectangle.new(corners: corners)
55
+ end
56
+
57
+ # Calculates the four corners of a rectangle given its width and height.
58
+ #
59
+ # @param x [Float] The x-coordinate of the rectangle's center.
60
+ # @param y [Float] The y-coordinate of the rectangle's center.
61
+ # @param width [Float] The width of the rectangle.
62
+ # @param height [Float] The height of the rectangle.
63
+ # @return [Array<Array<Float>>] Array of coordinates representing the rectangle's corners.
64
+ def self.calculate_corners(point, size)
65
+ half_width = size.width / 2
66
+ half_height = size.height / 2
67
+
68
+ offsets = [
69
+ [-half_width, -half_height], # Top-left
70
+ [half_width, -half_height], # Top-right
71
+ [half_width, half_height], # Bottom-right
72
+ [-half_width, half_height] # Bottom-left
73
+ ]
74
+
75
+ offsets.map { |dx, dy| Point.new(x: point.x + dx, y: point.y + dy) }
76
+ end
77
+
78
+ # Rotates the given corners of a rectangle around its center.
79
+ #
80
+ # @param corners [Array<Array<Float>>] Array of rectangle corner coordinates.
81
+ # @param rotation [Float] The rotation angle in degrees.
82
+ # @param center [Float] The center point of the image.
83
+ # @return [Array<Array<Float>>] Array of rotated corner coordinates.
84
+ def self.rotate_corners(corners, rotation, center)
85
+ rad_rotation = rotation * Math::PI / 180
86
+
87
+ corners.map do |point|
88
+ rotate_point(point, rad_rotation, center)
89
+ end
90
+ end
91
+
92
+ private_class_method def self.rotate_point(point, rad_rotation, center)
93
+ point.x -= center
94
+ point.y -= center
95
+ cos_theta = Math.cos(rad_rotation)
96
+ sin_theta = Math.sin(rad_rotation)
97
+
98
+ [
99
+ (cos_theta * point.x) - (sin_theta * point.y) + center,
100
+ (sin_theta * point.x) + (cos_theta * point.y) + center
101
+ ]
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "chunky_png"
4
+
5
+ module Jazzicon
6
+ # The Jazzicon::ImageHelpers module provides methods for adjusting the whole image.
7
+ module ImageHelpers
8
+ # Crops the image to a perfect circle.
9
+ #
10
+ # @param image [ChunkyPNG::Image] The image to crop.
11
+ # @param diameter [Integer] The diameter of the circle.
12
+ def self.crop_to_circle(image, diameter)
13
+ center = diameter / 2.0
14
+ radius = diameter / 2.0
15
+
16
+ image.height.times do |y|
17
+ image.width.times do |x|
18
+ # Check if the pixel is outside the circle
19
+ outside = (((x - center)**2) + ((y - center)**2)) > radius**2
20
+ image.set_pixel(x, y, ChunkyPNG::Color::TRANSPARENT) if outside
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "chunky_png"
4
+ require "digest"
5
+
6
+ require_relative "helpers/color_helpers"
7
+ require_relative "helpers/geometry_helpers"
8
+ require_relative "helpers/image_helpers"
9
+
10
+ module Jazzicon
11
+ COLORS = [
12
+ "#01888C", "#FC7500", "#34E90B", "#FF4A4A",
13
+ "#662E9B", "#FC7500", "#0284C7", "#A0D911",
14
+ "#A855F7", "#FF7875"
15
+ ].freeze
16
+ Iteration = Struct.new(:index, :color, :random_numbers, keyword_init: true)
17
+
18
+ # The Jazzicon::Icon class provides functionality to generate jazzy and colorful identicons.
19
+ # These identicons are generated based on a given seed and can be customized by specifying the diameter and the number
20
+ # of shapes that make up the icon.
21
+ #
22
+ # The main steps involved in generating an icon include:
23
+ # - Hashing the seed to ensure deterministic randomness.
24
+ # - Randomly selecting and hue-shifting colors.
25
+ # - Generating and combining multiple layers of shapes (rectangles) to create a visually distinctive pattern.
26
+ # - Cropping the image into a circular form.
27
+ #
28
+ # Key Features:
29
+ # - Deterministic: The same seed always produces the same icon.
30
+ # - Customizable: Supports customization of diameter and shape count.
31
+ #
32
+ # Dependencies:
33
+ # - `chunky_png`: Used for image creation and manipulation.
34
+ #
35
+ # Example Usage:
36
+ # ```
37
+ # require "jazzicon/icon"
38
+ #
39
+ # seed = "example-seed"
40
+ # diameter = 500
41
+ # shape_count = 4
42
+ #
43
+ # icon = Jazzicon::Icon.generate(seed, diameter: diameter, shape_count: shape_count)
44
+ # icon.save("icon.png")
45
+ # ```
46
+ class Icon
47
+ # Generates a unique icon based on the given seed.
48
+ #
49
+ # @param seed [String, Integer] The input seed used to generate the icon.
50
+ # @param diameter [Integer] The diameter of the generated icon.
51
+ # @param shape_count [Integer] The number of shapes to include in the icon.
52
+ # @return [ChunkyPNG::Image] The generated icon image.
53
+ def self.generate(seed, diameter: 500, shape_count: 4)
54
+ random = random(seed)
55
+ colors = ColorHelpers.hue_shift(COLORS.shuffle(random: random), random)
56
+
57
+ final_image = ChunkyPNG::Image.new(diameter, diameter, colors.delete(colors.sample(random: random)))
58
+
59
+ # Generate each shape and adds it
60
+ iterations(shape_count, colors, random).each do |iteration|
61
+ rec = GeometryHelpers.random_rectangle(diameter, iteration.index, shape_count, iteration.random_numbers)
62
+ final_image.polygon(rec.corners, iteration.color, iteration.color)
63
+ end
64
+
65
+ # Crop to a perfect circle
66
+ ImageHelpers.crop_to_circle(final_image, diameter)
67
+
68
+ # Profit!$!
69
+ final_image
70
+ end
71
+
72
+ private_class_method def self.random(seed)
73
+ # Hash the seed if it is a string
74
+ seed = Digest::SHA256.hexdigest(seed).to_i(16) if seed.is_a?(String)
75
+ Random.new(seed)
76
+ end
77
+
78
+ private_class_method def self.iterations(shape_count, colors, random)
79
+ (0...shape_count).map do |i|
80
+ Iteration.new(
81
+ index: i,
82
+ color: colors.delete(colors.sample(random: random)),
83
+ random_numbers: 3.times.map { random.rand }
84
+ )
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jazzicon
4
+ VERSION = "0.1.0"
5
+ end
data/lib/jazzicon.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "jazzicon/version"
4
+ require "jazzicon/icon"
5
+
6
+ module Jazzicon
7
+ class Error < StandardError; end
8
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jazzicon
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Stephen Heuer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-01-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: chunky_png
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.4'
27
+ description: Jazzicon is a Ruby implementation of the javascript Jazzicon identicon
28
+ generator (https://github.com/danfinlay/jazzicon).
29
+ email:
30
+ - sheuer@aruxsoftware.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files:
34
+ - README.md
35
+ - LICENSE.txt
36
+ files:
37
+ - LICENSE.txt
38
+ - README.md
39
+ - lib/jazzicon.rb
40
+ - lib/jazzicon/helpers/color_helpers.rb
41
+ - lib/jazzicon/helpers/geometry_helpers.rb
42
+ - lib/jazzicon/helpers/image_helpers.rb
43
+ - lib/jazzicon/icon.rb
44
+ - lib/jazzicon/version.rb
45
+ homepage: https://github.com/Arux-Software/jazzicon_ruby
46
+ licenses:
47
+ - MIT
48
+ metadata:
49
+ homepage_uri: https://github.com/Arux-Software/jazzicon_ruby
50
+ source_code_uri: https://github.com/Arux-Software/jazzicon_ruby
51
+ rubygems_mfa_required: 'true'
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 2.3.0
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubygems_version: 3.2.3
68
+ signing_key:
69
+ specification_version: 4
70
+ summary: A Ruby implementation of the javascript Jazzicon identicon generator.
71
+ test_files: []