pxlsrt 1.6.1 → 1.6.2

Sign up to get free protection for your applications and to get access to all the features.
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