pxlsrt 1.6.1 → 1.6.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.
data/lib/pxlsrt/colors.rb CHANGED
@@ -1,160 +1,160 @@
1
- require "oily_png"
2
-
3
- module Pxlsrt
4
- ##
5
- # Includes color operations.
6
- class Colors
7
- ##
8
- # Converts a ChunkyPNG pixel into an array of the red, green, blue, and alpha values
9
- def self.getRGBA(pxl)
10
- return [ChunkyPNG::Color.r(pxl), ChunkyPNG::Color.g(pxl), ChunkyPNG::Color.b(pxl), ChunkyPNG::Color.a(pxl)]
11
- end
12
- ##
13
- # Check if file is a PNG image. ChunkyPNG only works with PNG images. Eventually, I might use conversion tools to add support, but not right now.
14
- def self.isPNG?(path)
15
- return File.read(path).bytes==[137, 80, 78, 71, 10]
16
- end
17
- ##
18
- # Converts an RGB-like array ([red, green, blue]) into an HSB-like array ([hue, saturation, brightness]).
19
- def self.rgb2hsb(rgb)
20
- r = rgb[0] / 255.0
21
- g = rgb[1] / 255.0
22
- b = rgb[2] / 255.0
23
- max = [r, g, b].max
24
- min = [r, g, b].min
25
- delta = max - min
26
- v = max * 100
27
- if (max != 0.0)
28
- s = delta / max *100
29
- else
30
- s = 0.0
31
- end
32
- if (s == 0.0)
33
- h = 0.0
34
- else
35
- if (r == max)
36
- h = (g - b) / delta
37
- elsif (g == max)
38
- h = 2 + (b - r) / delta
39
- elsif (b == max)
40
- h = 4 + (r - g) / delta
41
- end
42
- h *= 60.0
43
- if (h < 0)
44
- h += 360.0
45
- end
46
- end
47
- return [h,s,v]
48
- end
49
- ##
50
- # Averages an array of RGB-like arrays.
51
- def self.colorAverage(ca, chunky = false)
52
- if ca.length==1
53
- return ca.first
54
- end
55
- Pxlsrt::Helpers.verbose(ca) if ca.length == 0
56
- if !chunky
57
- r=((ca.collect { |c| c[0] }).inject{ |sum, el| sum+el }).to_f / ca.size
58
- g=((ca.collect { |c| c[1] }).inject{ |sum, el| sum+el }).to_f / ca.size
59
- b=((ca.collect { |c| c[2] }).inject{ |sum, el| sum+el }).to_f / ca.size
60
- a=((ca.collect { |c| c[3] }).inject{ |sum, el| sum+el }).to_f / ca.size
61
- return [r.to_i, g.to_i, b.to_i, a.to_i]
62
- else
63
- r=((ca.collect { |c| ChunkyPNG::Color.r(c) }).inject{ |sum, el| sum+el }).to_f / ca.size
64
- g=((ca.collect { |c| ChunkyPNG::Color.g(c) }).inject{ |sum, el| sum+el }).to_f / ca.size
65
- b=((ca.collect { |c| ChunkyPNG::Color.b(c) }).inject{ |sum, el| sum+el }).to_f / ca.size
66
- a=((ca.collect { |c| ChunkyPNG::Color.a(c) }).inject{ |sum, el| sum+el }).to_f / ca.size
67
- return ChunkyPNG::Color.rgba(r.to_i, g.to_i, b.to_i, a.to_i)
68
- end
69
- end
70
- ##
71
- # Determines color distance from each other using the Pythagorean theorem.
72
- def self.colorDistance(c1,c2,chunky = false)
73
- if !chunky
74
- return Math.sqrt((c1[0]-c2[0])**2+(c1[1]-c2[1])**2+(c1[2]-c2[2])**2+(c1[3]-c2[3])**2)
75
- else
76
- return Math.sqrt((ChunkyPNG::Color.r(c1)-ChunkyPNG::Color.r(c2))**2+(ChunkyPNG::Color.g(c1)-ChunkyPNG::Color.g(c2))**2+(ChunkyPNG::Color.b(c1)-ChunkyPNG::Color.b(c2))**2+(ChunkyPNG::Color.a(c1)-ChunkyPNG::Color.a(c2))**2)
77
- end
78
- end
79
- ##
80
- # Uses a combination of color averaging and color distance to find how "unique" a color is.
81
- def self.colorUniqueness(c, ca, chunky = false)
82
- return Pxlsrt::Colors.colorDistance(c, Pxlsrt::Colors.colorAverage(ca, chunky), chunky)
83
- end
84
- ##
85
- # Sorts an array of colors based on a method.
86
- # Available methods:
87
- # * sum-rgb (default)
88
- # * sum-rgba
89
- # * red
90
- # * yellow
91
- # * green
92
- # * cyan
93
- # * blue
94
- # * magenta
95
- # * hue
96
- # * saturation
97
- # * brightness
98
- # * sum-hsb
99
- # * sum-hsba
100
- # * uniqueness
101
- # * luma
102
- # * random
103
- # * alpha
104
- def self.pixelSort(list, how, reverse)
105
- mhm=[]
106
- Pxlsrt::Helpers.error(list) if list.length == 0
107
- case how.downcase
108
- when "sum-rgb"
109
- mhm= list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.g(c)+ChunkyPNG::Color.b(c) }
110
- when "sum-rgba"
111
- mhm=list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.g(c)+ChunkyPNG::Color.b(c)+ChunkyPNG::Color.a(c) }
112
- when "red"
113
- mhm= list.sort_by { |c| ChunkyPNG::Color.r(c) }
114
- when "yellow"
115
- mhm=list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.g(c) }
116
- when "green"
117
- mhm= list.sort_by { |c| ChunkyPNG::Color.g(c) }
118
- when "cyan"
119
- mhm=list.sort_by { |c| ChunkyPNG::Color.g(c)+ChunkyPNG::Color.b(c) }
120
- when "blue"
121
- mhm= list.sort_by { |c| ChunkyPNG::Color.b(c) }
122
- when "magenta"
123
- mhm=list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.b(c) }
124
- when "hue"
125
- mhm= list.sort_by { |c| d = Pxlsrt::Colors.getRGBA(c); Pxlsrt::Colors.rgb2hsb(d)[0] }
126
- when "saturation"
127
- mhm= list.sort_by { |c| d = Pxlsrt::Colors.getRGBA(c); Pxlsrt::Colors.rgb2hsb(d)[1] }
128
- when "brightness"
129
- mhm= list.sort_by { |c| d = Pxlsrt::Colors.getRGBA(c); Pxlsrt::Colors.rgb2hsb(d)[2] }
130
- when "sum-hsb"
131
- mhm= list.sort_by { |c| d = Pxlsrt::Colors.getRGBA(c); k=Pxlsrt::Colors.rgb2hsb(d); k[0]*100.0/360+k[1]+k[2] }
132
- when "sum-hsba"
133
- mhm= list.sort_by { |c| d = Pxlsrt::Colors.getRGBA(c); k=Pxlsrt::Colors.rgb2hsb(d); k[0]*100.0/360+k[1]+k[2]+d.a*100.0/255 }
134
- when "uniqueness"
135
- avg=Pxlsrt::Colors.colorAverage(list, true)
136
- mhm=list.sort_by { |c| Pxlsrt::Colors.colorUniqueness(c, [avg], true) }
137
- when "luma"
138
- mhm=list.sort_by { |c| ChunkyPNG::Color.r(c)*0.2126+ChunkyPNG::Color.g(c)*0.7152+ChunkyPNG::Color.b(c)*0.0722 }
139
- when "random"
140
- mhm=list.shuffle
141
- when "alpha"
142
- mhm=list.sort_by{ |c| ChunkyPNG::Color.a(c) }
143
- else
144
- mhm= list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.g(c)+ChunkyPNG::Color.b(c) }
145
- end
146
- if reverse == 0
147
- return mhm
148
- elsif reverse == 1
149
- return mhm.reverse
150
- else
151
- return rand(0..1)==0 ? mhm : mhm.reverse
152
- end
153
- end
154
- ##
155
- # Turns an RGB-like array into ChunkyPNG's color
156
- def self.arrayToRGBA(a)
157
- return ChunkyPNG::Color.rgba(a[0], a[1], a[2], a[3])
158
- end
159
- end
1
+ require "oily_png"
2
+
3
+ module Pxlsrt
4
+ ##
5
+ # Includes color operations.
6
+ class Colors
7
+ ##
8
+ # Converts a ChunkyPNG pixel into an array of the red, green, blue, and alpha values
9
+ def self.getRGBA(pxl)
10
+ return [ChunkyPNG::Color.r(pxl), ChunkyPNG::Color.g(pxl), ChunkyPNG::Color.b(pxl), ChunkyPNG::Color.a(pxl)]
11
+ end
12
+ ##
13
+ # Check if file is a PNG image. ChunkyPNG only works with PNG images. Eventually, I might use conversion tools to add support, but not right now.
14
+ def self.isPNG?(path)
15
+ return File.open(path, 'rb').read(9).include?('PNG')
16
+ end
17
+ ##
18
+ # Converts an RGB-like array ([red, green, blue]) into an HSB-like array ([hue, saturation, brightness]).
19
+ def self.rgb2hsb(rgb)
20
+ r = rgb[0] / 255.0
21
+ g = rgb[1] / 255.0
22
+ b = rgb[2] / 255.0
23
+ max = [r, g, b].max
24
+ min = [r, g, b].min
25
+ delta = max - min
26
+ v = max * 100
27
+ if (max != 0.0)
28
+ s = delta / max *100
29
+ else
30
+ s = 0.0
31
+ end
32
+ if (s == 0.0)
33
+ h = 0.0
34
+ else
35
+ if (r == max)
36
+ h = (g - b) / delta
37
+ elsif (g == max)
38
+ h = 2 + (b - r) / delta
39
+ elsif (b == max)
40
+ h = 4 + (r - g) / delta
41
+ end
42
+ h *= 60.0
43
+ if (h < 0)
44
+ h += 360.0
45
+ end
46
+ end
47
+ return [h,s,v]
48
+ end
49
+ ##
50
+ # Averages an array of RGB-like arrays.
51
+ def self.colorAverage(ca, chunky = false)
52
+ if ca.length==1
53
+ return ca.first
54
+ end
55
+ Pxlsrt::Helpers.verbose(ca) if ca.length == 0
56
+ if !chunky
57
+ r=((ca.collect { |c| c[0] }).inject{ |sum, el| sum+el }).to_f / ca.size
58
+ g=((ca.collect { |c| c[1] }).inject{ |sum, el| sum+el }).to_f / ca.size
59
+ b=((ca.collect { |c| c[2] }).inject{ |sum, el| sum+el }).to_f / ca.size
60
+ a=((ca.collect { |c| c[3] }).inject{ |sum, el| sum+el }).to_f / ca.size
61
+ return [r.to_i, g.to_i, b.to_i, a.to_i]
62
+ else
63
+ r=((ca.collect { |c| ChunkyPNG::Color.r(c) }).inject{ |sum, el| sum+el }).to_f / ca.size
64
+ g=((ca.collect { |c| ChunkyPNG::Color.g(c) }).inject{ |sum, el| sum+el }).to_f / ca.size
65
+ b=((ca.collect { |c| ChunkyPNG::Color.b(c) }).inject{ |sum, el| sum+el }).to_f / ca.size
66
+ a=((ca.collect { |c| ChunkyPNG::Color.a(c) }).inject{ |sum, el| sum+el }).to_f / ca.size
67
+ return ChunkyPNG::Color.rgba(r.to_i, g.to_i, b.to_i, a.to_i)
68
+ end
69
+ end
70
+ ##
71
+ # Determines color distance from each other using the Pythagorean theorem.
72
+ def self.colorDistance(c1,c2,chunky = false)
73
+ if !chunky
74
+ return Math.sqrt((c1[0]-c2[0])**2+(c1[1]-c2[1])**2+(c1[2]-c2[2])**2+(c1[3]-c2[3])**2)
75
+ else
76
+ return Math.sqrt((ChunkyPNG::Color.r(c1)-ChunkyPNG::Color.r(c2))**2+(ChunkyPNG::Color.g(c1)-ChunkyPNG::Color.g(c2))**2+(ChunkyPNG::Color.b(c1)-ChunkyPNG::Color.b(c2))**2+(ChunkyPNG::Color.a(c1)-ChunkyPNG::Color.a(c2))**2)
77
+ end
78
+ end
79
+ ##
80
+ # Uses a combination of color averaging and color distance to find how "unique" a color is.
81
+ def self.colorUniqueness(c, ca, chunky = false)
82
+ return Pxlsrt::Colors.colorDistance(c, Pxlsrt::Colors.colorAverage(ca, chunky), chunky)
83
+ end
84
+ ##
85
+ # Sorts an array of colors based on a method.
86
+ # Available methods:
87
+ # * sum-rgb (default)
88
+ # * sum-rgba
89
+ # * red
90
+ # * yellow
91
+ # * green
92
+ # * cyan
93
+ # * blue
94
+ # * magenta
95
+ # * hue
96
+ # * saturation
97
+ # * brightness
98
+ # * sum-hsb
99
+ # * sum-hsba
100
+ # * uniqueness
101
+ # * luma
102
+ # * random
103
+ # * alpha
104
+ def self.pixelSort(list, how, reverse)
105
+ mhm=[]
106
+ Pxlsrt::Helpers.error(list) if list.length == 0
107
+ case how.downcase
108
+ when "sum-rgb"
109
+ mhm= list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.g(c)+ChunkyPNG::Color.b(c) }
110
+ when "sum-rgba"
111
+ mhm=list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.g(c)+ChunkyPNG::Color.b(c)+ChunkyPNG::Color.a(c) }
112
+ when "red"
113
+ mhm= list.sort_by { |c| ChunkyPNG::Color.r(c) }
114
+ when "yellow"
115
+ mhm=list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.g(c) }
116
+ when "green"
117
+ mhm= list.sort_by { |c| ChunkyPNG::Color.g(c) }
118
+ when "cyan"
119
+ mhm=list.sort_by { |c| ChunkyPNG::Color.g(c)+ChunkyPNG::Color.b(c) }
120
+ when "blue"
121
+ mhm= list.sort_by { |c| ChunkyPNG::Color.b(c) }
122
+ when "magenta"
123
+ mhm=list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.b(c) }
124
+ when "hue"
125
+ mhm= list.sort_by { |c| d = Pxlsrt::Colors.getRGBA(c); Pxlsrt::Colors.rgb2hsb(d)[0] }
126
+ when "saturation"
127
+ mhm= list.sort_by { |c| d = Pxlsrt::Colors.getRGBA(c); Pxlsrt::Colors.rgb2hsb(d)[1] }
128
+ when "brightness"
129
+ mhm= list.sort_by { |c| d = Pxlsrt::Colors.getRGBA(c); Pxlsrt::Colors.rgb2hsb(d)[2] }
130
+ when "sum-hsb"
131
+ mhm= list.sort_by { |c| d = Pxlsrt::Colors.getRGBA(c); k=Pxlsrt::Colors.rgb2hsb(d); k[0]*100.0/360+k[1]+k[2] }
132
+ when "sum-hsba"
133
+ mhm= list.sort_by { |c| d = Pxlsrt::Colors.getRGBA(c); k=Pxlsrt::Colors.rgb2hsb(d); k[0]*100.0/360+k[1]+k[2]+d.a*100.0/255 }
134
+ when "uniqueness"
135
+ avg=Pxlsrt::Colors.colorAverage(list, true)
136
+ mhm=list.sort_by { |c| Pxlsrt::Colors.colorUniqueness(c, [avg], true) }
137
+ when "luma"
138
+ mhm=list.sort_by { |c| ChunkyPNG::Color.r(c)*0.2126+ChunkyPNG::Color.g(c)*0.7152+ChunkyPNG::Color.b(c)*0.0722 }
139
+ when "random"
140
+ mhm=list.shuffle
141
+ when "alpha"
142
+ mhm=list.sort_by{ |c| ChunkyPNG::Color.a(c) }
143
+ else
144
+ mhm= list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.g(c)+ChunkyPNG::Color.b(c) }
145
+ end
146
+ if reverse == 0
147
+ return mhm
148
+ elsif reverse == 1
149
+ return mhm.reverse
150
+ else
151
+ return rand(0..1)==0 ? mhm : mhm.reverse
152
+ end
153
+ end
154
+ ##
155
+ # Turns an RGB-like array into ChunkyPNG's color
156
+ def self.arrayToRGBA(a)
157
+ return ChunkyPNG::Color.rgba(a[0], a[1], a[2], a[3])
158
+ end
159
+ end
160
160
  end
@@ -1,94 +1,94 @@
1
- module Pxlsrt
2
- ##
3
- # Methods not having to do with image or color manipulation.
4
- class Helpers
5
- ##
6
- # Determines if a value has content.
7
- def self.contented(c)
8
- return (c.class!=NilClass and ((defined? c)!="nil") and ((/(\S)/.match("#{c}"))!=nil))
9
- end
10
- ##
11
- # Used to output a red string to the terminal.
12
- def self.red(what)
13
- return "\e[31m#{what}\e[0m"
14
- end
15
- ##
16
- # Used to output a cyan string to the terminal.
17
- def self.cyan(what)
18
- return "\e[36m#{what}\e[0m"
19
- end
20
- ##
21
- # Determines if a string can be a float or integer.
22
- def self.isNumeric?(s)
23
- true if Float(s) rescue false
24
- end
25
- ##
26
- # Checks if supplied options follow the rules.
27
- def self.checkOptions(options, rules)
28
- match=true
29
- for o in options.keys
30
- o_match=false
31
- if rules[o].class==Array
32
- if rules[o].include?(options[o])
33
- o_match=true
34
- else
35
- for r in 0...rules[o].length
36
- if rules[o][r].class==Hash
37
- for n in rules[o][r][:class]
38
- if n==options[o].class
39
- o_match=match
40
- break
41
- end
42
- end
43
- end
44
- if o_match==true
45
- break
46
- end
47
- end
48
- end
49
- elsif rules[o] == :anything
50
- o_match = true
51
- end
52
- match=(match and o_match)
53
- if match==false
54
- break
55
- end
56
- end
57
- return match
58
- end
59
- ##
60
- # Pixel sorting helper to eliminate repetition.
61
- def self.handlePixelSort(band, o)
62
- if (o[:reverse].class == String and (o[:reverse].downcase == "reverse" or o[:reverse] == "")) or o[:reverse] == true
63
- reverse = 1
64
- elsif o[:reverse].class == String and o[:reverse].downcase == "either"
65
- reverse = -1
66
- else
67
- reverse = 0
68
- end
69
- if o[:smooth]
70
- u = band.group_by { |x| x }
71
- k = u.keys
72
- else
73
- k = band
74
- end
75
- sortedBand = Pxlsrt::Colors.pixelSort(
76
- k,
77
- o[:method],
78
- reverse
79
- )
80
- sortedBand = sortedBand.map { |x| u[x] }.flatten(1) if o[:smooth]
81
- return Pxlsrt::Lines.handleMiddlate(sortedBand, o[:middle])
82
- end
83
- ##
84
- # Prints an error message.
85
- def self.error(what)
86
- puts "#{Pxlsrt::Helpers.red("pxlsrt")} #{what}"
87
- end
88
- ##
89
- # Prints something.
90
- def self.verbose(what)
91
- puts "#{Pxlsrt::Helpers.cyan("pxlsrt")} #{what}"
92
- end
93
- end
1
+ module Pxlsrt
2
+ ##
3
+ # Methods not having to do with image or color manipulation.
4
+ class Helpers
5
+ ##
6
+ # Determines if a value has content.
7
+ def self.contented(c)
8
+ return c != nil
9
+ end
10
+ ##
11
+ # Used to output a red string to the terminal.
12
+ def self.red(what)
13
+ return "\e[31m#{what}\e[0m"
14
+ end
15
+ ##
16
+ # Used to output a cyan string to the terminal.
17
+ def self.cyan(what)
18
+ return "\e[36m#{what}\e[0m"
19
+ end
20
+ ##
21
+ # Determines if a string can be a float or integer.
22
+ def self.isNumeric?(s)
23
+ true if Float(s) rescue false
24
+ end
25
+ ##
26
+ # Checks if supplied options follow the rules.
27
+ def self.checkOptions(options, rules)
28
+ match=true
29
+ for o in options.keys
30
+ o_match=false
31
+ if rules[o].class==Array
32
+ if rules[o].include?(options[o])
33
+ o_match=true
34
+ else
35
+ for r in 0...rules[o].length
36
+ if rules[o][r].class==Hash
37
+ for n in rules[o][r][:class]
38
+ if n==options[o].class
39
+ o_match=match
40
+ break
41
+ end
42
+ end
43
+ end
44
+ if o_match==true
45
+ break
46
+ end
47
+ end
48
+ end
49
+ elsif rules[o] == :anything
50
+ o_match = true
51
+ end
52
+ match=(match and o_match)
53
+ if match==false
54
+ break
55
+ end
56
+ end
57
+ return match
58
+ end
59
+ ##
60
+ # Pixel sorting helper to eliminate repetition.
61
+ def self.handlePixelSort(band, o)
62
+ if (o[:reverse].class == String and (o[:reverse].downcase == "reverse" or o[:reverse] == "")) or o[:reverse] == true
63
+ reverse = 1
64
+ elsif o[:reverse].class == String and o[:reverse].downcase == "either"
65
+ reverse = -1
66
+ else
67
+ reverse = 0
68
+ end
69
+ if o[:smooth]
70
+ u = band.group_by { |x| x }
71
+ k = u.keys
72
+ else
73
+ k = band
74
+ end
75
+ sortedBand = Pxlsrt::Colors.pixelSort(
76
+ k,
77
+ o[:method],
78
+ reverse
79
+ )
80
+ sortedBand = sortedBand.map { |x| u[x] }.flatten(1) if o[:smooth]
81
+ return Pxlsrt::Lines.handleMiddlate(sortedBand, o[:middle])
82
+ end
83
+ ##
84
+ # Prints an error message.
85
+ def self.error(what)
86
+ puts "#{Pxlsrt::Helpers.red("pxlsrt")} #{what}"
87
+ end
88
+ ##
89
+ # Prints something.
90
+ def self.verbose(what)
91
+ puts "#{Pxlsrt::Helpers.cyan("pxlsrt")} #{what}"
92
+ end
93
+ end
94
94
  end