abachrome 0.1.0 → 0.1.2

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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +3 -0
  3. data/README.md +10 -0
  4. data/Rakefile +15 -0
  5. data/devenv.lock +88 -17
  6. data/devenv.nix +2 -1
  7. data/devenv.yaml +5 -12
  8. data/lib/abachrome/abc_decimal.rb +201 -7
  9. data/lib/abachrome/color.rb +88 -1
  10. data/lib/abachrome/color_mixins/blend.rb +53 -2
  11. data/lib/abachrome/color_mixins/lighten.rb +49 -2
  12. data/lib/abachrome/color_mixins/to_colorspace.rb +67 -2
  13. data/lib/abachrome/color_mixins/to_lrgb.rb +70 -2
  14. data/lib/abachrome/color_mixins/to_oklab.rb +67 -2
  15. data/lib/abachrome/color_mixins/to_oklch.rb +60 -2
  16. data/lib/abachrome/color_mixins/to_srgb.rb +77 -2
  17. data/lib/abachrome/color_models/hsv.rb +25 -2
  18. data/lib/abachrome/color_models/lms.rb +34 -0
  19. data/lib/abachrome/color_models/oklab.rb +19 -2
  20. data/lib/abachrome/color_models/oklch.rb +42 -2
  21. data/lib/abachrome/color_models/rgb.rb +28 -2
  22. data/lib/abachrome/color_models/xyz.rb +28 -0
  23. data/lib/abachrome/color_space.rb +88 -2
  24. data/lib/abachrome/converter.rb +56 -2
  25. data/lib/abachrome/converters/base.rb +69 -2
  26. data/lib/abachrome/converters/lms_to_lrgb.rb +36 -0
  27. data/lib/abachrome/converters/lms_to_srgb.rb +23 -0
  28. data/lib/abachrome/converters/lms_to_xyz.rb +30 -0
  29. data/lib/abachrome/converters/lrgb_to_lms.rb +0 -0
  30. data/lib/abachrome/converters/lrgb_to_oklab.rb +28 -2
  31. data/lib/abachrome/converters/lrgb_to_srgb.rb +27 -2
  32. data/lib/abachrome/converters/lrgb_to_xyz.rb +29 -0
  33. data/lib/abachrome/converters/oklab_to_lms.rb +41 -0
  34. data/lib/abachrome/converters/oklab_to_lrgb.rb +56 -29
  35. data/lib/abachrome/converters/oklab_to_oklch.rb +31 -2
  36. data/lib/abachrome/converters/oklab_to_srgb.rb +27 -2
  37. data/lib/abachrome/converters/oklch_to_lrgb.rb +66 -6
  38. data/lib/abachrome/converters/oklch_to_oklab.rb +29 -4
  39. data/lib/abachrome/converters/oklch_to_srgb.rb +26 -2
  40. data/lib/abachrome/converters/oklch_to_xyz.rb +66 -0
  41. data/lib/abachrome/converters/srgb_to_lrgb.rb +26 -2
  42. data/lib/abachrome/converters/srgb_to_oklab.rb +28 -2
  43. data/lib/abachrome/converters/srgb_to_oklch.rb +27 -2
  44. data/lib/abachrome/converters/xyz_to_lms.rb +30 -0
  45. data/lib/abachrome/converters/xyz_to_oklab.rb +38 -0
  46. data/lib/abachrome/gamut/base.rb +2 -2
  47. data/lib/abachrome/gamut/p3.rb +2 -2
  48. data/lib/abachrome/gamut/rec2020.rb +2 -2
  49. data/lib/abachrome/gamut/srgb.rb +20 -2
  50. data/lib/abachrome/illuminants/base.rb +2 -2
  51. data/lib/abachrome/illuminants/d50.rb +2 -2
  52. data/lib/abachrome/illuminants/d55.rb +2 -2
  53. data/lib/abachrome/illuminants/d65.rb +2 -2
  54. data/lib/abachrome/illuminants/d75.rb +2 -2
  55. data/lib/abachrome/named/css.rb +149 -158
  56. data/lib/abachrome/outputs/css.rb +2 -2
  57. data/lib/abachrome/palette.rb +112 -2
  58. data/lib/abachrome/palette_mixins/interpolate.rb +20 -2
  59. data/lib/abachrome/palette_mixins/resample.rb +2 -2
  60. data/lib/abachrome/palette_mixins/stretch_luminance.rb +2 -2
  61. data/lib/abachrome/parsers/hex.rb +2 -2
  62. data/lib/abachrome/to_abcd.rb +10 -2
  63. data/lib/abachrome/version.rb +2 -2
  64. data/lib/abachrome.rb +78 -2
  65. data/logo.png +0 -0
  66. data/logo.webp +0 -0
  67. metadata +26 -67
@@ -1,164 +1,155 @@
1
- # frozen_string_literal: true
2
-
3
- # Colors courtesy of w3c:
4
- # https://www.w3.org/wiki/CSS/Properties/color/keywords
5
1
  #
2
+
6
3
  module Abachrome
7
4
  module Named
8
5
  module CSS
9
- ColorNames = {
10
- "aliceblue" => [240, 248, 255],
11
- "antiquewhite" => [250, 235, 215],
12
- "aqua" => [0, 255, 255],
13
- "aquamarine" => [127, 255, 212],
14
- "azure" => [240, 255, 255],
15
- "beige" => [245, 245, 220],
16
- "bisque" => [255, 228, 196],
17
- "black" => [0, 0, 0],
18
- "blanchedalmond" => [255, 235, 205],
19
- "blue" => [0, 0, 255],
20
- "blueviolet" => [138, 43, 226],
21
- "brown" => [165, 42, 42],
22
- "burlywood" => [222, 184, 135],
23
- "cadetblue" => [95, 158, 160],
24
- "chartreuse" => [127, 255, 0],
25
- "chocolate" => [210, 105, 30],
26
- "coral" => [255, 127, 80],
27
- "cornflowerblue" => [100, 149, 237],
28
- "cornsilk" => [255, 248, 220],
29
- "crimson" => [220, 20, 60],
30
- "cyan" => [0, 255, 255],
31
- "darkblue" => [0, 0, 139],
32
- "darkcyan" => [0, 139, 139],
33
- "darkgoldenrod" => [184, 134, 11],
34
- "darkgray" => [169, 169, 169],
35
- "darkgreen" => [0, 100, 0],
36
- "darkgrey" => [169, 169, 169],
37
- "darkkhaki" => [189, 183, 107],
38
- "darkmagenta" => [139, 0, 139],
39
- "darkolivegreen" => [85, 107, 47],
40
- "darkorange" => [255, 140, 0],
41
- "darkorchid" => [153, 50, 204],
42
- "darkred" => [139, 0, 0],
43
- "darksalmon" => [233, 150, 122],
44
- "darkseagreen" => [143, 188, 143],
45
- "darkslateblue" => [72, 61, 139],
46
- "darkslategray" => [47, 79, 79],
47
- "darkslategrey" => [47, 79, 79],
48
- "darkturquoise" => [0, 206, 209],
49
- "darkviolet" => [148, 0, 211],
50
- "deeppink" => [255, 20, 147],
51
- "deepskyblue" => [0, 191, 255],
52
- "dimgray" => [105, 105, 105],
53
- "dimgrey" => [105, 105, 105],
54
- "dodgerblue" => [30, 144, 255],
55
- "firebrick" => [178, 34, 34],
56
- "floralwhite" => [255, 250, 240],
57
- "forestgreen" => [34, 139, 34],
58
- "fuchsia" => [255, 0, 255],
59
- "gainsboro" => [220, 220, 220],
60
- "ghostwhite" => [248, 248, 255],
61
- "gold" => [255, 215, 0],
62
- "goldenrod" => [218, 165, 32],
63
- "gray" => [128, 128, 128],
64
- "green" => [0, 128, 0],
65
- "greenyellow" => [173, 255, 47],
66
- "grey" => [128, 128, 128],
67
- "honeydew" => [240, 255, 240],
68
- "hotpink" => [255, 105, 180],
69
- "indianred" => [205, 92, 92],
70
- "indigo" => [75, 0, 130],
71
- "ivory" => [255, 255, 240],
72
- "khaki" => [240, 230, 140],
73
- "lavender" => [230, 230, 250],
74
- "lavenderblush" => [255, 240, 245],
75
- "lawngreen" => [124, 252, 0],
76
- "lemonchiffon" => [255, 250, 205],
77
- "lightblue" => [173, 216, 230],
78
- "lightcoral" => [240, 128, 128],
79
- "lightcyan" => [224, 255, 255],
80
- "lightgoldenrodyellow" => [250, 250, 210],
81
- "lightgray" => [211, 211, 211],
82
- "lightgreen" => [144, 238, 144],
83
- "lightgrey" => [211, 211, 211],
84
- "lightpink" => [255, 182, 193],
85
- "lightsalmon" => [255, 160, 122],
86
- "lightseagreen" => [32, 178, 170],
87
- "lightskyblue" => [135, 206, 250],
88
- "lightslategray" => [119, 136, 153],
89
- "lightslategrey" => [119, 136, 153],
90
- "lightsteelblue" => [176, 196, 222],
91
- "lightyellow" => [255, 255, 224],
92
- "lime" => [0, 255, 0],
93
- "limegreen" => [50, 205, 50],
94
- "linen" => [250, 240, 230],
95
- "magenta" => [255, 0, 255],
96
- "maroon" => [128, 0, 0],
97
- "mediumaquamarine" => [102, 205, 170],
98
- "mediumblue" => [0, 0, 205],
99
- "mediumorchid" => [186, 85, 211],
100
- "mediumpurple" => [147, 112, 219],
101
- "mediumseagreen" => [60, 179, 113],
102
- "mediumslateblue" => [123, 104, 238],
103
- "mediumspringgreen" => [0, 250, 154],
104
- "mediumturquoise" => [72, 209, 204],
105
- "mediumvioletred" => [199, 21, 133],
106
- "midnightblue" => [25, 25, 112],
107
- "mintcream" => [245, 255, 250],
108
- "mistyrose" => [255, 228, 225],
109
- "moccasin" => [255, 228, 181],
110
- "navajowhite" => [255, 222, 173],
111
- "navy" => [0, 0, 128],
112
- "oldlace" => [253, 245, 230],
113
- "olive" => [128, 128, 0],
114
- "olivedrab" => [107, 142, 35],
115
- "orange" => [255, 165, 0],
116
- "orangered" => [255, 69, 0],
117
- "orchid" => [218, 112, 214],
118
- "palegoldenrod" => [238, 232, 170],
119
- "palegreen" => [152, 251, 152],
120
- "paleturquoise" => [175, 238, 238],
121
- "palevioletred" => [219, 112, 147],
122
- "papayawhip" => [255, 239, 213],
123
- "peachpuff" => [255, 218, 185],
124
- "peru" => [205, 133, 63],
125
- "pink" => [255, 192, 203],
126
- "plum" => [221, 160, 221],
127
- "powderblue" => [176, 224, 230],
128
- "purple" => [128, 0, 128],
129
- "red" => [255, 0, 0],
130
- "rosybrown" => [188, 143, 143],
131
- "royalblue" => [65, 105, 225],
132
- "saddlebrown" => [139, 69, 19],
133
- "salmon" => [250, 128, 114],
134
- "sandybrown" => [244, 164, 96],
135
- "seagreen" => [46, 139, 87],
136
- "seashell" => [255, 245, 238],
137
- "sienna" => [160, 82, 45],
138
- "silver" => [192, 192, 192],
139
- "skyblue" => [135, 206, 235],
140
- "slateblue" => [106, 90, 205],
141
- "slategray" => [112, 128, 144],
142
- "slategrey" => [112, 128, 144],
143
- "snow" => [255, 250, 250],
144
- "springgreen" => [0, 255, 127],
145
- "steelblue" => [70, 130, 180],
146
- "tan" => [210, 180, 140],
147
- "teal" => [0, 128, 128],
148
- "thistle" => [216, 191, 216],
149
- "tomato" => [255, 99, 71],
150
- "turquoise" => [64, 224, 208],
151
- "violet" => [238, 130, 238],
152
- "wheat" => [245, 222, 179],
153
- "white" => [255, 255, 255],
154
- "whitesmoke" => [245, 245, 245],
155
- "yellow" => [255, 255, 0],
156
- "yellowgreen" => [154, 205, 50]
157
- }.freeze
158
-
159
- def method_missing(name, *args, &block)
160
- ColorNames[name] || super
161
- end
6
+ def self.aliceblue; [240, 248, 255] end
7
+ def self.antiquewhite; [250, 235, 215] end
8
+ def self.aqua; [0, 255, 255] end
9
+ def self.aquamarine; [127, 255, 212] end
10
+ def self.azure; [240, 255, 255] end
11
+ def self.beige; [245, 245, 220] end
12
+ def self.bisque; [255, 228, 196] end
13
+ def self.black; [0, 0, 0] end
14
+ def self.blanchedalmond; [255, 235, 205] end
15
+ def self.blue; [0, 0, 255] end
16
+ def self.blueviolet; [138, 43, 226] end
17
+ def self.brown; [165, 42, 42] end
18
+ def self.burlywood; [222, 184, 135] end
19
+ def self.cadetblue; [95, 158, 160] end
20
+ def self.chartreuse; [127, 255, 0] end
21
+ def self.chocolate; [210, 105, 30] end
22
+ def self.coral; [255, 127, 80] end
23
+ def self.cornflowerblue; [100, 149, 237] end
24
+ def self.cornsilk; [255, 248, 220] end
25
+ def self.crimson; [220, 20, 60] end
26
+ def self.cyan; [0, 255, 255] end
27
+ def self.darkblue; [0, 0, 139] end
28
+ def self.darkcyan; [0, 139, 139] end
29
+ def self.darkgoldenrod; [184, 134, 11] end
30
+ def self.darkgray; [169, 169, 169] end
31
+ def self.darkgreen; [0, 100, 0] end
32
+ def self.darkgrey; [169, 169, 169] end
33
+ def self.darkkhaki; [189, 183, 107] end
34
+ def self.darkmagenta; [139, 0, 139] end
35
+ def self.darkolivegreen; [85, 107, 47] end
36
+ def self.darkorange; [255, 140, 0] end
37
+ def self.darkorchid; [153, 50, 204] end
38
+ def self.darkred; [139, 0, 0] end
39
+ def self.darksalmon; [233, 150, 122] end
40
+ def self.darkseagreen; [143, 188, 143] end
41
+ def self.darkslateblue; [72, 61, 139] end
42
+ def self.darkslategray; [47, 79, 79] end
43
+ def self.darkslategrey; [47, 79, 79] end
44
+ def self.darkturquoise; [0, 206, 209] end
45
+ def self.darkviolet; [148, 0, 211] end
46
+ def self.deeppink; [255, 20, 147] end
47
+ def self.deepskyblue; [0, 191, 255] end
48
+ def self.dimgray; [105, 105, 105] end
49
+ def self.dimgrey; [105, 105, 105] end
50
+ def self.dodgerblue; [30, 144, 255] end
51
+ def self.firebrick; [178, 34, 34] end
52
+ def self.floralwhite; [255, 250, 240] end
53
+ def self.forestgreen; [34, 139, 34] end
54
+ def self.fuchsia; [255, 0, 255] end
55
+ def self.gainsboro; [220, 220, 220] end
56
+ def self.ghostwhite; [248, 248, 255] end
57
+ def self.gold; [255, 215, 0] end
58
+ def self.goldenrod; [218, 165, 32] end
59
+ def self.gray; [128, 128, 128] end
60
+ def self.green; [0, 128, 0] end
61
+ def self.greenyellow; [173, 255, 47] end
62
+ def self.grey; [128, 128, 128] end
63
+ def self.honeydew; [240, 255, 240] end
64
+ def self.hotpink; [255, 105, 180] end
65
+ def self.indianred; [205, 92, 92] end
66
+ def self.indigo; [75, 0, 130] end
67
+ def self.ivory; [255, 255, 240] end
68
+ def self.khaki; [240, 230, 140] end
69
+ def self.lavender; [230, 230, 250] end
70
+ def self.lavenderblush; [255, 240, 245] end
71
+ def self.lawngreen; [124, 252, 0] end
72
+ def self.lemonchiffon; [255, 250, 205] end
73
+ def self.lightblue; [173, 216, 230] end
74
+ def self.lightcoral; [240, 128, 128] end
75
+ def self.lightcyan; [224, 255, 255] end
76
+ def self.lightgoldenrodyellow; [250, 250, 210] end
77
+ def self.lightgray; [211, 211, 211] end
78
+ def self.lightgreen; [144, 238, 144] end
79
+ def self.lightgrey; [211, 211, 211] end
80
+ def self.lightpink; [255, 182, 193] end
81
+ def self.lightsalmon; [255, 160, 122] end
82
+ def self.lightseagreen; [32, 178, 170] end
83
+ def self.lightskyblue; [135, 206, 250] end
84
+ def self.lightslategray; [119, 136, 153] end
85
+ def self.lightslategrey; [119, 136, 153] end
86
+ def self.lightsteelblue; [176, 196, 222] end
87
+ def self.lightyellow; [255, 255, 224] end
88
+ def self.lime; [0, 255, 0] end
89
+ def self.limegreen; [50, 205, 50] end
90
+ def self.linen; [250, 240, 230] end
91
+ def self.magenta; [255, 0, 255] end
92
+ def self.maroon; [128, 0, 0] end
93
+ def self.mediumaquamarine; [102, 205, 170] end
94
+ def self.mediumblue; [0, 0, 205] end
95
+ def self.mediumorchid; [186, 85, 211] end
96
+ def self.mediumpurple; [147, 112, 219] end
97
+ def self.mediumseagreen; [60, 179, 113] end
98
+ def self.mediumslateblue; [123, 104, 238] end
99
+ def self.mediumspringgreen; [0, 250, 154] end
100
+ def self.mediumturquoise; [72, 209, 204] end
101
+ def self.mediumvioletred; [199, 21, 133] end
102
+ def self.midnightblue; [25, 25, 112] end
103
+ def self.mintcream; [245, 255, 250] end
104
+ def self.mistyrose; [255, 228, 225] end
105
+ def self.moccasin; [255, 228, 181] end
106
+ def self.navajowhite; [255, 222, 173] end
107
+ def self.navy; [0, 0, 128] end
108
+ def self.oldlace; [253, 245, 230] end
109
+ def self.olive; [128, 128, 0] end
110
+ def self.olivedrab; [107, 142, 35] end
111
+ def self.orange; [255, 165, 0] end
112
+ def self.orangered; [255, 69, 0] end
113
+ def self.orchid; [218, 112, 214] end
114
+ def self.palegoldenrod; [238, 232, 170] end
115
+ def self.palegreen; [152, 251, 152] end
116
+ def self.paleturquoise; [175, 238, 238] end
117
+ def self.palevioletred; [219, 112, 147] end
118
+ def self.papayawhip; [255, 239, 213] end
119
+ def self.peachpuff; [255, 218, 185] end
120
+ def self.peru; [205, 133, 63] end
121
+ def self.pink; [255, 192, 203] end
122
+ def self.plum; [221, 160, 221] end
123
+ def self.powderblue; [176, 224, 230] end
124
+ def self.purple; [128, 0, 128] end
125
+ def self.red; [255, 0, 0] end
126
+ def self.rosybrown; [188, 143, 143] end
127
+ def self.royalblue; [65, 105, 225] end
128
+ def self.saddlebrown; [139, 69, 19] end
129
+ def self.salmon; [250, 128, 114] end
130
+ def self.sandybrown; [244, 164, 96] end
131
+ def self.seagreen; [46, 139, 87] end
132
+ def self.seashell; [255, 245, 238] end
133
+ def self.sienna; [160, 82, 45] end
134
+ def self.silver; [192, 192, 192] end
135
+ def self.skyblue; [135, 206, 235] end
136
+ def self.slateblue; [106, 90, 205] end
137
+ def self.slategray; [112, 128, 144] end
138
+ def self.slategrey; [112, 128, 144] end
139
+ def self.snow; [255, 250, 250] end
140
+ def self.springgreen; [0, 255, 127] end
141
+ def self.steelblue; [70, 130, 180] end
142
+ def self.tan; [210, 180, 140] end
143
+ def self.teal; [0, 128, 128] end
144
+ def self.thistle; [216, 191, 216] end
145
+ def self.tomato; [255, 99, 71] end
146
+ def self.turquoise; [64, 224, 208] end
147
+ def self.violet; [238, 130, 238] end
148
+ def self.wheat; [245, 222, 179] end
149
+ def self.white; [255, 255, 255] end
150
+ def self.whitesmoke; [245, 245, 245] end
151
+ def self.yellow; [255, 255, 0] end
152
+ def self.yellowgreen; [154, 205, 50] end
162
153
  end
163
154
  end
164
- end
155
+ end
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: true
1
+ #
2
2
 
3
3
  require_relative "../color"
4
4
  require_relative "../color_space"
@@ -114,4 +114,4 @@ module Abachrome
114
114
  end
115
115
  end
116
116
  end
117
- end
117
+ end
@@ -1,13 +1,26 @@
1
- # frozen_string_literal: true
1
+ #
2
2
 
3
3
  module Abachrome
4
4
  class Palette
5
5
  attr_reader :colors
6
6
 
7
+ # Initializes a new color palette with the given colors.
8
+ # Automatically converts non-Color objects to Color objects by parsing them as hex values.
9
+ #
10
+ # @param colors [Array] An array of colors to include in the palette. Each element can be
11
+ # either a Color object or a string-convertible object representing a hex color code.
12
+ # @return [Abachrome::Palette] A new palette instance containing the provided colors.
7
13
  def initialize(colors = [])
8
14
  @colors = colors.map { |c| c.is_a?(Color) ? c : Color.from_hex(c.to_s) }
9
15
  end
10
16
 
17
+ # Adds a color to the palette.
18
+ # Accepts either an Abachrome::Color object or any object that can be
19
+ # converted to a string and parsed as a hex color code.
20
+ #
21
+ # @param color [Abachrome::Color, String, #to_s] The color to add to the palette.
22
+ # If not already an Abachrome::Color object, it will be converted using Color.from_hex
23
+ # @return [Abachrome::Palette] self, enabling method chaining
11
24
  def add(color)
12
25
  color = Color.from_hex(color.to_s) unless color.is_a?(Color)
13
26
  @colors << color
@@ -16,64 +29,141 @@ module Abachrome
16
29
 
17
30
  alias << add
18
31
 
32
+ # Removes the specified color from the palette.
33
+ #
34
+ # @param color [Abachrome::Color, Object] The color to be removed from the palette
35
+ # @return [Abachrome::Palette] Returns self for method chaining
19
36
  def remove(color)
20
37
  @colors.delete(color)
21
38
  self
22
39
  end
23
40
 
41
+ # Clears all colors from the palette.
42
+ #
43
+ # This method removes all stored colors in the palette. It provides a way to
44
+ # reset the palette to an empty state while maintaining the same palette object.
45
+ #
46
+ # @return [Abachrome::Palette] Returns self for method chaining
24
47
  def clear
25
48
  @colors.clear
26
49
  self
27
50
  end
28
51
 
52
+ # Returns the number of colors in the palette.
53
+ #
54
+ # @return [Integer] the number of colors in the palette
29
55
  def size
30
56
  @colors.size
31
57
  end
32
58
 
59
+ # Returns whether the palette has no colors.
60
+ #
61
+ # @return [Boolean] true if the palette contains no colors, false otherwise
33
62
  def empty?
34
63
  @colors.empty?
35
64
  end
36
65
 
66
+ # Yields each color in the palette to the given block.
67
+ #
68
+ # @param block [Proc] The block to be executed for each color in the palette.
69
+ # @yield [Abachrome::Color] Each color in the palette.
70
+ # @return [Enumerator] Returns an Enumerator if no block is given.
71
+ # @see Enumerable#each
37
72
  def each(&block)
38
73
  @colors.each(&block)
39
74
  end
75
+ # Calls the given block once for each color in the palette, passing the color and its index as parameters.
76
+ #
77
+ # @example
78
+ # palette.each_with_index { |color, index| puts "Color #{index}: #{color}" }
79
+ #
80
+ # @param block [Proc] The block to be called for each color
81
+ # @yield [color, index] Yields a color and its index
82
+ # @yieldparam color [Abachrome::Color] The color at the current position
83
+ # @yieldparam index [Integer] The index of the current color
84
+ # @return [Enumerator] If no block is given, returns an Enumerator
85
+ # @return [Array<Abachrome::Color>] Returns the array of colors if a block is given
40
86
  def each_with_index(&block)
41
87
  @colors.each_with_index(&block)
42
88
  end
43
89
 
90
+ # Maps the palette by applying a block to each color.
91
+ #
92
+ # @param block [Proc] A block that takes a color and returns a new color.
93
+ # @return [Abachrome::Palette] A new palette with the mapped colors.
94
+ # @example
95
+ # # Convert all colors in palette to grayscale
96
+ # palette.map { |color| color.grayscale }
44
97
  def map(&block)
45
98
  self.class.new(@colors.map(&block))
46
99
  end
47
100
 
101
+ # Returns a duplicate of the internal colors array.
102
+ #
103
+ # @return [Array<Abachrome::Color>] A duplicate of the palette's color array
48
104
  def to_a
49
105
  @colors.dup
50
106
  end
51
107
 
108
+ # Access a color in the palette at the specified index.
109
+ #
110
+ # @param index [Integer] The index of the color to retrieve from the palette
111
+ # @return [Abachrome::Color, nil] The color at the specified index, or nil if the index is out of bounds
52
112
  def [](index)
53
113
  @colors[index]
54
114
  end
55
115
 
116
+ # Slices the palette to create a new palette with a subset of colors.
117
+ #
118
+ # @param start [Integer] The starting index (or range) from which to start the slice.
119
+ # @param length [Integer, nil] The number of colors to include in the slice. If nil and start is an Integer,
120
+ # returns a new palette containing the single color at that index. If start is a Range, length is ignored.
121
+ # @return [Abachrome::Palette] A new palette containing the selected colors.
56
122
  def slice(start, length = nil)
57
123
  new_colors = length ? @colors[start, length] : @colors[start]
58
124
  self.class.new(new_colors)
59
125
  end
60
126
 
127
+ # Returns the first color in the palette.
128
+ #
129
+ # @return [Abachrome::Color, nil] The first color in the palette, or nil if the palette is empty.
61
130
  def first
62
131
  @colors.first
63
132
  end
64
133
 
134
+ # Returns the last color in the palette.
135
+ #
136
+ # @return [Abachrome::Color, nil] The last color in the palette or nil if palette is empty.
65
137
  def last
66
138
  @colors.last
67
139
  end
68
140
 
141
+ # Returns a new palette with colors sorted by lightness.
142
+ # This method creates a new palette instance containing the same colors as the current
143
+ # palette but sorted in ascending order based on their lightness values.
144
+ #
145
+ # @return [Abachrome::Palette] a new palette with the same colors sorted by lightness
69
146
  def sort_by_lightness
70
147
  self.class.new(@colors.sort_by(&:lightness))
71
148
  end
72
149
 
150
+ # Returns a new palette with colors sorted by saturation from lowest to highest.
151
+ # Saturation is determined by the second coordinate (a*) in the OKLAB color space.
152
+ # Lower values represent less saturated colors, higher values represent more saturated colors.
153
+ #
154
+ # @return [Abachrome::Palette] A new palette instance with the same colors sorted by saturation
73
155
  def sort_by_saturation
74
156
  self.class.new(@colors.sort_by { |c| c.to_oklab.coordinates[1] })
75
157
  end
76
158
 
159
+ # Blends all colors in the palette together sequentially at the specified amount.
160
+ # This method takes each color in the palette and blends it with the accumulated result
161
+ # of previous blends. It starts with the first color and progressively blends each subsequent
162
+ # color at the specified blend amount.
163
+ #
164
+ # @param amount [Float] The blend amount to use between each color pair, between 0.0 and 1.0.
165
+ # Defaults to 0.5 (equal blend).
166
+ # @return [Abachrome::Color, nil] The final blended color result, or nil if the palette is empty.
77
167
  def blend_all(amount = 0.5)
78
168
  return nil if empty?
79
169
 
@@ -84,6 +174,13 @@ module Abachrome
84
174
  result
85
175
  end
86
176
 
177
+ # Calculates the average color of the palette by finding the centroid in OKLAB space.
178
+ # This method converts each color in the palette to OKLAB coordinates,
179
+ # calculates the arithmetic mean of these coordinates, and creates a new
180
+ # color from the average values. Alpha values are also averaged.
181
+ #
182
+ # @return [Abachrome::Color, nil] The average color of all colors in the palette,
183
+ # or nil if the palette is empty
87
184
  def average
88
185
  return nil if empty?
89
186
 
@@ -100,6 +197,16 @@ module Abachrome
100
197
  )
101
198
  end
102
199
 
200
+ # Converts the colors in the palette to CSS-formatted strings.
201
+ #
202
+ # The format of the output can be specified with the format parameter.
203
+ #
204
+ # @param format [Symbol] The format to use for the CSS color strings.
205
+ # :hex - Outputs colors in hexadecimal format (e.g., "#RRGGBB")
206
+ # :rgb - Outputs colors in rgb() function format
207
+ # :oklab - Outputs colors in oklab() function format
208
+ # When any other value is provided, a default format is used.
209
+ # @return [Array<String>] An array of CSS-formatted color strings
103
210
  def to_css(format: :hex)
104
211
  to_a.map do |color|
105
212
  case format
@@ -115,6 +222,9 @@ module Abachrome
115
222
  end
116
223
  end
117
224
 
225
+ # Returns a string representation of the palette for inspection purposes.
226
+ #
227
+ # @return [String] A string containing the class name and a list of colors in the palette
118
228
  def inspect
119
229
  "#<#{self.class} colors=#{@colors.map(&:to_s)}>"
120
230
  end
@@ -128,4 +238,4 @@ module Abachrome
128
238
  include mixin_module
129
239
  end
130
240
  end
131
- end
241
+ end
@@ -1,4 +1,22 @@
1
- # frozen_string_literal: true
1
+ # Abachrome::PaletteMixins::Interpolate - Color palette interpolation functionality
2
+ #
3
+ # This mixin provides methods for interpolating between adjacent colors in a palette to create
4
+ # smooth color transitions and gradients. The interpolation process inserts new colors between
5
+ # existing palette colors by blending them at calculated intervals, creating smoother color
6
+ # progressions ideal for gradients, color ramps, and visual transitions.
7
+ #
8
+ # Key features:
9
+ # - Insert specified number of interpolated colors between each adjacent color pair
10
+ # - Both non-destructive (interpolate) and destructive (interpolate!) variants
11
+ # - Uses color blending in the current color space for smooth transitions
12
+ # - Maintains original colors as anchor points in the interpolated result
13
+ # - High-precision decimal arithmetic for accurate color calculations
14
+ # - Preserves alpha values during interpolation process
15
+ #
16
+ # The mixin includes both immutable methods that return new palette instances and mutable
17
+ # methods that modify the current palette object in place, providing flexibility for
18
+ # different use cases and performance requirements. Interpolation is essential for creating
19
+ # smooth color gradients and ensuring adequate color resolution in palette-based applications.
2
20
 
3
21
  module Abachrome
4
22
  module PaletteMixins
@@ -28,4 +46,4 @@ module Abachrome
28
46
  end
29
47
  end
30
48
  end
31
- end
49
+ end
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: true
1
+ #
2
2
 
3
3
  module Abachrome
4
4
  module PaletteMixins
@@ -56,4 +56,4 @@ module Abachrome
56
56
  end
57
57
  end
58
58
  end
59
- end
59
+ end
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: true
1
+ #
2
2
 
3
3
  module Abachrome
4
4
  module PaletteMixins
@@ -67,4 +67,4 @@ module Abachrome
67
67
  end
68
68
  end
69
69
  end
70
- end
70
+ end
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: true
1
+ #
2
2
 
3
3
  module Abachrome
4
4
  module Parsers
@@ -47,4 +47,4 @@ module Abachrome
47
47
  end
48
48
  end
49
49
  end
50
- end
50
+ end