jazzicon 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []