pxlsrt 1.6.3 → 1.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 61530233928fdf5537158612c19fb3709da5281d
4
- data.tar.gz: fbda0d61a84d109a8f97865db731a9cf369f6db8
3
+ metadata.gz: 5a70f5d32502428d68f198d43c0ee703814b0827
4
+ data.tar.gz: 213ac35f136cf0de3cc07329e7ced721a47df470
5
5
  SHA512:
6
- metadata.gz: b94363170de2be0c0dc41dc5c8d9430edb443c5981e33df4480895740c5108ee9f192857d59c053bba645df8097bee539470c14fb54746836f395004e9e38c49
7
- data.tar.gz: d503edbbbdd822c1f4f6f2894a1d7983e1f21735d414a090759e5f9f5817c624cbc8982de1fa2a1bfc791dbecaacd8ec91de7522fc8e68ea84c3e22a2bc0852a
6
+ metadata.gz: 8b492703dd354aead349520473721db2a8ef810e9495fa7b8e4b6e2d362a4083496b563be6c8204d5cee8c6cb915a08ac933bbe77253a9b767ea2e95d407a9af
7
+ data.tar.gz: 9f2c0daebb6336b7dd56222c8eb04b03957d0cc3b5e9735a5e77593b56de6bb71e1de6e3309638390eaa49109f28ae7ddd743c30f6391b6e9398c4adfbf8d5f8
data/bin/pxlsrt CHANGED
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'rubygems'
4
3
  require 'pxlsrt'
5
4
  require 'thor'
6
5
 
@@ -14,14 +13,14 @@ require 'thor'
14
13
  # * verbose - Have pxlsrt tell you what it's working on.
15
14
  # * help - More in depth commands.
16
15
  class CLI < Thor
17
- class_option :reverse, :default => false, :aliases => "-r"
18
- class_option :vertical, :type => :boolean, :default => false, :aliases => "-v"
19
- class_option :diagonal, :type => :boolean, :default => false, :aliases => "-d"
20
- class_option :smooth, :type => :boolean, :default => false, :aliases => "-s"
21
- class_option :method, :type => :string, :default => "sum-rgb", :banner => "[sum-rgb | red | green | blue | sum-hsb | hue | saturation | brightness | uniqueness | luma | random | cyan | magenta | yellow | alpha | sum-rgba | sum-hsba]", :aliases => "-m", :enum => ["sum-rgb", "red", "green", "blue", "sum-hsb", "hue", "saturation", "brightness", "uniqueness", "luma", "random", "cyan", "magenta", "yellow", "alpha", "sum-rgba", "sum-hsba"]
22
16
  class_option :verbose, :type => :boolean, :default => false, :aliases => "-V"
23
- class_option :middle, :default => false, :aliases => "-M"
24
17
 
18
+ option :reverse, :default => false, :aliases => "-r"
19
+ option :vertical, :type => :boolean, :default => false, :aliases => "-v"
20
+ option :diagonal, :type => :boolean, :default => false, :aliases => "-d"
21
+ option :smooth, :type => :boolean, :default => false, :aliases => "-s"
22
+ option :method, :type => :string, :default => "sum-rgb", :banner => "[#{Pxlsrt::Colors::METHODS.join(" | ")}]", :aliases => "-m", :enum => Pxlsrt::Colors::METHODS
23
+ option :middle, :default => false, :aliases => "-M"
25
24
  option :min, :type => :numeric, :default => Float::INFINITY, :banner => "MINIMUM BANDWIDTH"
26
25
  option :max, :type => :numeric, :default => Float::INFINITY, :banner => "MAXIMUM BANDWIDTH"
27
26
  desc "brute INPUT OUTPUT [options]", "Brute pixel sorting"
@@ -37,6 +36,12 @@ class CLI < Thor
37
36
  Pxlsrt::Brute.suite(input, output, k)
38
37
  end
39
38
 
39
+ option :reverse, :default => false, :aliases => "-r"
40
+ option :vertical, :type => :boolean, :default => false, :aliases => "-v"
41
+ option :diagonal, :type => :boolean, :default => false, :aliases => "-d"
42
+ option :smooth, :type => :boolean, :default => false, :aliases => "-s"
43
+ option :method, :type => :string, :default => "sum-rgb", :banner => "[#{Pxlsrt::Colors::METHODS.join(" | ")}]", :aliases => "-m", :enum => Pxlsrt::Colors::METHODS
44
+ option :middle, :default => false, :aliases => "-M"
40
45
  option :absolute, :type => :boolean, :default => false, :aliases => "-a", :banner => "ABSOLUTE EDGE FINDING"
41
46
  option :threshold, :type => :numeric, :default => 20, :aliases => "-t"
42
47
  desc "smart INPUT OUTPUT [options]", "Smart pixel sorting"
@@ -51,6 +56,17 @@ class CLI < Thor
51
56
  end
52
57
  Pxlsrt::Smart.suite(input, output, k)
53
58
  end
59
+
60
+ option :method, :type => :string, :default => "brightness", :aliases => "-m", :enum => ["brightness", "white", "black"]
61
+ option :value, :type => :numeric, :aliases => "-v"
62
+ desc "kim INPUT OUTPUT [outputs]", "Uses Kim Asendorf's algorithm"
63
+ def kim(input, output)
64
+ k= {:trusted => true}
65
+ for o in options.keys
66
+ k[o.to_sym] = options[o]
67
+ end
68
+ Pxlsrt::Kim.suite(input, output, k)
69
+ end
54
70
  end
55
71
 
56
72
  CLI.start(ARGV)
@@ -4,4 +4,5 @@ require "pxlsrt/lines"
4
4
  require "pxlsrt/image"
5
5
  require "pxlsrt/colors"
6
6
  require "pxlsrt/brute"
7
- require "pxlsrt/smart"
7
+ require "pxlsrt/smart"
8
+ require "pxlsrt/kim"
@@ -1,4 +1,3 @@
1
- require 'rubygems'
2
1
  require 'oily_png'
3
2
 
4
3
  module Pxlsrt
@@ -15,7 +14,7 @@ module Pxlsrt
15
14
  end
16
15
  end
17
16
  ##
18
- # The main attraction of the Brute class. Returns a ChunkyPNG::Image that is sorted according to the options provided. Will return nil if it encounters an errors.
17
+ # The main attraction of the Brute class. Returns a ChunkyPNG::Image that is sorted according to the options provided. Will raise any error that occurs.
19
18
  def self.brute(input, o={})
20
19
  startTime=Time.now
21
20
  defOptions={
@@ -35,7 +34,7 @@ module Pxlsrt
35
34
  :vertical => [false, true],
36
35
  :diagonal => [false, true],
37
36
  :smooth => [false, true],
38
- :method => ["sum-rgb", "red", "green", "blue", "sum-hsb", "hue", "saturation", "brightness", "uniqueness", "luma", "random", "cyan", "magenta", "yellow", "alpha", "sum-rgba", "sum-hsba"],
37
+ :method => Pxlsrt::Colors::METHODS,
39
38
  :verbose => [false, true],
40
39
  :min => [Float::INFINITY, {:class => [Fixnum]}],
41
40
  :max => [Float::INFINITY, {:class => [Fixnum]}],
@@ -53,17 +52,14 @@ module Pxlsrt
53
52
  else
54
53
  Pxlsrt::Helpers.error("File #{input} is not a valid PNG.") if options[:verbose]
55
54
  raise "Invalid PNG"
56
- return
57
55
  end
58
56
  else
59
57
  Pxlsrt::Helpers.error("File #{input} doesn't exist!") if options[:verbose]
60
58
  raise "File doesn't exit"
61
- return
62
59
  end
63
60
  elsif input.class!=String and input.class!=ChunkyPNG::Image
64
61
  Pxlsrt::Helpers.error("Input is not a filename or ChunkyPNG::Image") if options[:verbose]
65
62
  raise "Invalid input (must be filename or ChunkyPNG::Image)"
66
- return
67
63
  end
68
64
  Pxlsrt::Helpers.verbose("Brute mode.") if options[:verbose]
69
65
  Pxlsrt::Helpers.verbose("Creating Pxlsrt::Image object") if options[:verbose]
@@ -86,7 +82,9 @@ module Pxlsrt
86
82
  else
87
83
  iterator = lines.keys
88
84
  end
89
- Pxlsrt::Helpers.verbose("Dividing and pixel sorting lines") if options[:verbose]
85
+ prr = 0
86
+ len = iterator.to_a.length
87
+ Pxlsrt::Helpers.progress("Dividing and pixel sorting lines", prr, len) if options[:verbose]
90
88
  for k in iterator
91
89
  line = lines[k]
92
90
  divisions = Pxlsrt::Lines.randomSlices(line.length,options[:min],options[:max])
@@ -102,6 +100,8 @@ module Pxlsrt
102
100
  png.replaceDiagonal(k, newLine) if !options[:vertical]
103
101
  png.replaceRDiagonal(k, newLine) if options[:vertical]
104
102
  end
103
+ prr += 1
104
+ Pxlsrt::Helpers.progress("Dividing and pixel sorting lines", prr, len) if options[:verbose]
105
105
  end
106
106
  endTime=Time.now
107
107
  timeElapsed=endTime-startTime
@@ -117,7 +117,6 @@ module Pxlsrt
117
117
  else
118
118
  Pxlsrt::Helpers.error("Options specified do not follow the correct format.") if options[:verbose]
119
119
  raise "Bad options"
120
- return
121
120
  end
122
121
  end
123
122
  end
@@ -4,6 +4,9 @@ module Pxlsrt
4
4
  ##
5
5
  # Includes color operations.
6
6
  class Colors
7
+ ##
8
+ # List of sorting methods.
9
+ METHODS = ["sum-rgb", "red", "green", "blue", "sum-hsb", "hue", "saturation", "brightness", "uniqueness", "luma", "random", "cyan", "magenta", "yellow", "alpha", "sum-rgba", "sum-hsba"]
7
10
  ##
8
11
  # Converts a ChunkyPNG pixel into an array of the red, green, blue, and alpha values
9
12
  def self.getRGBA(pxl)
@@ -15,38 +18,6 @@ module Pxlsrt
15
18
  return File.open(path, 'rb').read(9).include?('PNG')
16
19
  end
17
20
  ##
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
21
  # Averages an array of RGB-like arrays.
51
22
  def self.colorAverage(ca, chunky = false)
52
23
  if ca.length==1
@@ -106,49 +77,49 @@ module Pxlsrt
106
77
  Pxlsrt::Helpers.error(list) if list.length == 0
107
78
  case how.downcase
108
79
  when "sum-rgb"
109
- mhm= list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.g(c)+ChunkyPNG::Color.b(c) }
80
+ mhm = list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.g(c)+ChunkyPNG::Color.b(c) }
110
81
  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) }
82
+ mhm =list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.g(c)+ChunkyPNG::Color.b(c)+ChunkyPNG::Color.a(c) }
112
83
  when "red"
113
- mhm= list.sort_by { |c| ChunkyPNG::Color.r(c) }
84
+ mhm = list.sort_by { |c| ChunkyPNG::Color.r(c) }
114
85
  when "yellow"
115
- mhm=list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.g(c) }
86
+ mhm =list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.g(c) }
116
87
  when "green"
117
- mhm= list.sort_by { |c| ChunkyPNG::Color.g(c) }
88
+ mhm = list.sort_by { |c| ChunkyPNG::Color.g(c) }
118
89
  when "cyan"
119
- mhm=list.sort_by { |c| ChunkyPNG::Color.g(c)+ChunkyPNG::Color.b(c) }
90
+ mhm =list.sort_by { |c| ChunkyPNG::Color.g(c)+ChunkyPNG::Color.b(c) }
120
91
  when "blue"
121
- mhm= list.sort_by { |c| ChunkyPNG::Color.b(c) }
92
+ mhm = list.sort_by { |c| ChunkyPNG::Color.b(c) }
122
93
  when "magenta"
123
- mhm=list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.b(c) }
94
+ mhm =list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.b(c) }
124
95
  when "hue"
125
- mhm= list.sort_by { |c| d = Pxlsrt::Colors.getRGBA(c); Pxlsrt::Colors.rgb2hsb(d)[0] }
96
+ mhm = list.sort_by { |c| ChunkyPNG::Color.to_hsb(c)[0] % 360 }
126
97
  when "saturation"
127
- mhm= list.sort_by { |c| d = Pxlsrt::Colors.getRGBA(c); Pxlsrt::Colors.rgb2hsb(d)[1] }
98
+ mhm = list.sort_by { |c| ChunkyPNG::Color.to_hsb(c)[1] }
128
99
  when "brightness"
129
- mhm= list.sort_by { |c| d = Pxlsrt::Colors.getRGBA(c); Pxlsrt::Colors.rgb2hsb(d)[2] }
100
+ mhm = list.sort_by { |c| ChunkyPNG::Color.to_hsb(c)[2] }
130
101
  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] }
102
+ mhm = list.sort_by { |c| k = ChunkyPNG::Color.to_hsb(c); (k[0] % 360) / 360.0 + k[1] + k[2] }
132
103
  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 }
104
+ mhm = list.sort_by { |c| k = ChunkyPNG::Color.to_hsb(c); (k[0] % 360) / 360.0 + k[1] + k[2] + ChunkyPNG::Color.a(c) / 255.0 }
134
105
  when "uniqueness"
135
- avg=Pxlsrt::Colors.colorAverage(list, true)
136
- mhm=list.sort_by { |c| Pxlsrt::Colors.colorUniqueness(c, [avg], true) }
106
+ avg = Pxlsrt::Colors.colorAverage(list, true)
107
+ mhm = list.sort_by { |c| Pxlsrt::Colors.colorUniqueness(c, [avg], true) }
137
108
  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 }
109
+ mhm = list.sort_by { |c| ChunkyPNG::Color.r(c) * 0.2126 + ChunkyPNG::Color.g(c) * 0.7152 + ChunkyPNG::Color.b(c) * 0.0722 + ChunkyPNG::Color.a(c) }
139
110
  when "random"
140
- mhm=list.shuffle
111
+ mhm = list.shuffle
141
112
  when "alpha"
142
- mhm=list.sort_by{ |c| ChunkyPNG::Color.a(c) }
113
+ mhm = list.sort_by{ |c| ChunkyPNG::Color.a(c) }
143
114
  else
144
- mhm= list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.g(c)+ChunkyPNG::Color.b(c) }
115
+ mhm = list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.g(c)+ChunkyPNG::Color.b(c) }
145
116
  end
146
117
  if reverse == 0
147
118
  return mhm
148
119
  elsif reverse == 1
149
120
  return mhm.reverse
150
121
  else
151
- return rand(0..1)==0 ? mhm : mhm.reverse
122
+ return [true, false].sample ? mhm : mhm.reverse
152
123
  end
153
124
  end
154
125
  ##
@@ -18,6 +18,16 @@ module Pxlsrt
18
18
  return "\e[36m#{what}\e[0m"
19
19
  end
20
20
  ##
21
+ # Used to output a yellow string to the terminal.
22
+ def self.yellow(what)
23
+ return "\e[33m#{what}\e[0m"
24
+ end
25
+ ##
26
+ # Used to output a green string to the terminal.
27
+ def self.green(what)
28
+ return "\e[32m#{what}\e[0m"
29
+ end
30
+ ##
21
31
  # Determines if a string can be a float or integer.
22
32
  def self.isNumeric?(s)
23
33
  true if Float(s) rescue false
@@ -90,5 +100,16 @@ module Pxlsrt
90
100
  def self.verbose(what)
91
101
  puts "#{Pxlsrt::Helpers.cyan("pxlsrt")} #{what}"
92
102
  end
103
+ ##
104
+ # Progress indication.
105
+ def self.progress(what, amount, outof)
106
+ progress = (amount.to_f * 100.0 / outof.to_f).to_i
107
+ if progress == 100
108
+ puts "\r#{Pxlsrt::Helpers.green("pxlsrt")} #{what} (#{Pxlsrt::Helpers.green("#{progress}%")})"
109
+ else
110
+ $stdout.write "\r#{Pxlsrt::Helpers.yellow("pxlsrt")} #{what} (#{Pxlsrt::Helpers.yellow("#{progress}%")})"
111
+ $stdout.flush
112
+ end
113
+ end
93
114
  end
94
115
  end
@@ -158,6 +158,16 @@ module Pxlsrt
158
158
  def []=(x, y, color)
159
159
  @modified[x, y] = color
160
160
  end
161
+ def i(i)
162
+ x = i % @width
163
+ y = (i / @width).floor
164
+ return self[x, y]
165
+ end
166
+ def i=(i, color)
167
+ x = i % @width
168
+ y = (i / @width).floor
169
+ self[x, y] = color
170
+ end
161
171
  ##
162
172
  # Return the original, unmodified image.
163
173
  def returnOriginal
@@ -168,5 +178,11 @@ module Pxlsrt
168
178
  def returnModified
169
179
  return @modified
170
180
  end
181
+ def getWidth
182
+ return @width
183
+ end
184
+ def getHeight
185
+ return @height
186
+ end
171
187
  end
172
188
  end
@@ -0,0 +1,263 @@
1
+ require 'oily_png'
2
+
3
+ module Pxlsrt
4
+ ##
5
+ # Uses Kim Asendorf's pixel sorting algorithm, orginally written in Processing. https://github.com/kimasendorf/ASDFPixelSort
6
+ class Kim
7
+ ##
8
+ # Uses Pxlsrt::Kim.kim to input and output from one method.
9
+ def self.suite(inputFileName, outputFileName, o={})
10
+ kml=Pxlsrt::Kim.kim(inputFileName, o)
11
+ if Pxlsrt::Helpers.contented(kml)
12
+ kml.save(outputFileName)
13
+ end
14
+ end
15
+ ##
16
+ # The main attraction of the Kim class. Returns a ChunkyPNG::Image that is sorted according to the options provided. Will raise any error that occurs.
17
+ def self.kim(input, o = {})
18
+ startTime = Time.now
19
+ defOptions={
20
+ :method => "brightness",
21
+ :verbose => false,
22
+ :value => false,
23
+ :trusted => false
24
+ }
25
+ defRules = {
26
+ :method => ["brightness", "black", "white"],
27
+ :verbose => [false, true],
28
+ :value => [false, {:class => [Fixnum]}],
29
+ :trusted => [false, true]
30
+ }
31
+ options = defOptions.merge(o)
32
+ if o.length == 0 or options[:trusted] == true or (options[:trusted] == false and o.length != 0 and Pxlsrt::Helpers.checkOptions(options, defRules) != false)
33
+ if input.class == String
34
+ Pxlsrt::Helpers.verbose("Getting image from file...") if options[:verbose]
35
+ if File.file?(input)
36
+ if Pxlsrt::Colors.isPNG?(input)
37
+ input = ChunkyPNG::Image.from_file(input)
38
+ else
39
+ Pxlsrt::Helpers.error("File #{input} is not a valid PNG.") if options[:verbose]
40
+ raise "Invalid PNG"
41
+ end
42
+ else
43
+ Pxlsrt::Helpers.error("File #{input} doesn't exist!") if options[:verbose]
44
+ raise "File doesn't exit"
45
+ end
46
+ elsif input.class != String and input.class != ChunkyPNG::Image
47
+ Pxlsrt::Helpers.error("Input is not a filename or ChunkyPNG::Image") if options[:verbose]
48
+ raise "Invalid input (must be filename or ChunkyPNG::Image)"
49
+ end
50
+ Pxlsrt::Helpers.verbose("Kim Asendorf mode.") if options[:verbose]
51
+ Pxlsrt::Helpers.verbose("Creating Pxlsrt::Image object") if options[:verbose]
52
+ png = Pxlsrt::Image.new(input)
53
+ column = 0
54
+ row = 0
55
+ options[:value] ||= ChunkyPNG::Color.rgba(11, 220, 0, 1) if options[:method] == "black"
56
+ options[:value] ||= 60 if options[:method] == "brightness"
57
+ options[:value] ||= ChunkyPNG::Color.rgba(57, 167, 192, 1) if options[:method] == "white"
58
+ Pxlsrt::Helpers.progress("Sorting columns", column, png.getWidth) if options[:verbose]
59
+ while column < png.getWidth
60
+ x = column
61
+ y = 0
62
+ yend = 0
63
+ while yend < png.getHeight
64
+ case options[:method]
65
+ when "black"
66
+ y = self.getFirstNotBlackY(png, x, y, options[:value])
67
+ yend = self.getNextBlackY(png, x, y, options[:value])
68
+ when "brightness"
69
+ y = self.getFirstBrightY(png, x, y, options[:value])
70
+ yend = self.getNextDarkY(png, x, y, options[:value])
71
+ when "white"
72
+ y = self.getFirstNotWhiteY(png, x, y, options[:value])
73
+ yend = self.getNextWhiteY(png, x, y, options[:value])
74
+ end
75
+ if y < 0
76
+ break
77
+ end
78
+ sortLength = yend - y;
79
+ unsorted = []
80
+ sorted = []
81
+ for i in (0...sortLength)
82
+ unsorted[i] = png[x, y + i];
83
+ end
84
+ sorted = unsorted.sort
85
+ for i in (0...sortLength)
86
+ png[x, y + i] = sorted[i];
87
+ end
88
+ y = yend + 1;
89
+ end
90
+ column += 1
91
+ Pxlsrt::Helpers.progress("Sorting columns", column, png.getWidth) if options[:verbose]
92
+ end
93
+ Pxlsrt::Helpers.progress("Sorting rows", row, png.getHeight) if options[:verbose]
94
+ while row < png.getHeight
95
+ x = 0
96
+ y = row
97
+ xend = 0
98
+ while xend < png.getWidth
99
+ case options[:method]
100
+ when "black"
101
+ x = self.getFirstNotBlackX(png, x, y, options[:value])
102
+ xend = self.getNextBlackX(png, x, y, options[:value])
103
+ when "brightness"
104
+ x = self.getFirstBrightX(png, x, y, options[:value])
105
+ xend = self.getNextDarkX(png, x, y, options[:value])
106
+ when "white"
107
+ x = self.getFirstNotWhiteX(png, x, y, options[:value])
108
+ xend = self.getNextWhiteX(png, x, y, options[:value])
109
+ end
110
+ if x < 0
111
+ break
112
+ end
113
+ sortLength = xend - x
114
+ unsorted = []
115
+ sorted = []
116
+ for i in (0...sortLength)
117
+ unsorted[i] = png[x + i, y]
118
+ end
119
+ sorted = unsorted.sort
120
+ for i in (0...sortLength)
121
+ png[x + i, y] = sorted[i];
122
+ end
123
+ x = xend + 1;
124
+ end
125
+ row += 1
126
+ Pxlsrt::Helpers.progress("Sorting rows", row, png.getHeight) if options[:verbose]
127
+ end
128
+ endTime=Time.now
129
+ timeElapsed=endTime-startTime
130
+ if timeElapsed < 60
131
+ Pxlsrt::Helpers.verbose("Took #{timeElapsed.round(4)} second#{ timeElapsed!=1.0 ? "s" : "" }.") if options[:verbose]
132
+ else
133
+ minutes=(timeElapsed/60).floor
134
+ seconds=(timeElapsed % 60).round(4)
135
+ Pxlsrt::Helpers.verbose("Took #{minutes} minute#{ minutes!=1 ? "s" : "" } and #{seconds} second#{ seconds!=1.0 ? "s" : "" }.") if options[:verbose]
136
+ end
137
+ Pxlsrt::Helpers.verbose("Returning ChunkyPNG::Image...") if options[:verbose]
138
+ return png.returnModified
139
+ else
140
+ Pxlsrt::Helpers.error("Options specified do not follow the correct format.") if options[:verbose]
141
+ raise "Bad options"
142
+ end
143
+ end
144
+ # Helper methods
145
+ # Black
146
+ def self.getFirstNotBlackX(img, x, y, blackValue)
147
+ if x < img.getWidth
148
+ while img[x, y] < blackValue
149
+ x += 1
150
+ return -1 if x >= img.getWidth
151
+ end
152
+ end
153
+ return x
154
+ end
155
+ def self.getFirstNotBlackY(img, x, y, blackValue)
156
+ if y < img.getHeight
157
+ while img[x, y] < blackValue
158
+ y += 1
159
+ return -1 if y >= img.getHeight
160
+ end
161
+ end
162
+ return y
163
+ end
164
+ def self.getNextBlackX(img, x, y, blackValue)
165
+ x += 1
166
+ if x < img.getWidth
167
+ while img[x, y] > blackValue
168
+ x += 1
169
+ return (img.getWidth - 1) if x >= img.getWidth
170
+ end
171
+ end
172
+ return x - 1
173
+ end
174
+ def self.getNextBlackY(img, x, y, blackValue)
175
+ y += 1
176
+ if y < img.getHeight
177
+ while img[x, y] > blackValue
178
+ y += 1
179
+ return (img.getHeight - 1) if y >= img.getHeight
180
+ end
181
+ end
182
+ return y - 1
183
+ end
184
+ # Brightness
185
+ def self.getFirstBrightX(img, x, y, brightnessValue)
186
+ if x < img.getWidth
187
+ while ChunkyPNG::Color.to_hsb(img[x, y])[2] * 255 < brightnessValue
188
+ x += 1;
189
+ return -1 if x >= img.getWidth
190
+ end
191
+ end
192
+ return x
193
+ end
194
+ def self.getFirstBrightY(img, x, y, brightnessValue)
195
+ if y < img.getHeight
196
+ while ChunkyPNG::Color.to_hsb(img[x, y])[2] * 255 < brightnessValue
197
+ y += 1;
198
+ return -1 if y >= img.getHeight
199
+ end
200
+ end
201
+ return y
202
+ end
203
+ def self.getNextDarkX(img, x, y, brightnessValue)
204
+ x += 1
205
+ if x < img.getWidth
206
+ while ChunkyPNG::Color.to_hsb(img[x, y])[2] * 255 > brightnessValue
207
+ x += 1
208
+ return (img.getWidth - 1) if x >= img.getWidth
209
+ end
210
+ end
211
+ return x - 1
212
+ end
213
+ def self.getNextDarkY(img, x, y, brightnessValue)
214
+ y += 1
215
+ if y < img.getHeight
216
+ while ChunkyPNG::Color.to_hsb(img[x, y])[2] * 255 > brightnessValue
217
+ y += 1
218
+ return (img.getHeight - 1) if y >= img.getHeight
219
+ end
220
+ end
221
+ return y - 1
222
+ end
223
+ # White
224
+ def self.getFirstNotWhiteX(img, x, y, whiteValue)
225
+ if x < img.getWidth
226
+ while img[x, y] > whiteValue
227
+ x += 1
228
+ return -1 if x >= img.getWidth
229
+ end
230
+ end
231
+ return x
232
+ end
233
+ def self.getFirstNotWhiteY(img, x, y, whiteValue)
234
+ if y < img.getHeight
235
+ while img[x, y] > whiteValue
236
+ y += 1
237
+ return -1 if y >= img.getHeight
238
+ end
239
+ end
240
+ return y
241
+ end
242
+ def self.getNextWhiteX(img, x, y, whiteValue)
243
+ x += 1
244
+ if x < img.getWidth
245
+ while img[x, y] < whiteValue
246
+ x += 1
247
+ return (img.getWidth - 1) if x >= img.getWidth
248
+ end
249
+ end
250
+ return x - 1
251
+ end
252
+ def self.getNextWhiteY(img, x, y, whiteValue)
253
+ y += 1
254
+ if y < img.getHeight
255
+ while img[x, y] < whiteValue
256
+ y += 1
257
+ return (img.getHeight - 1) if y >= img.getHeight
258
+ end
259
+ end
260
+ return y - 1
261
+ end
262
+ end
263
+ end
@@ -1,4 +1,3 @@
1
- require 'rubygems'
2
1
  require 'oily_png'
3
2
 
4
3
  module Pxlsrt
@@ -16,7 +15,7 @@ module Pxlsrt
16
15
  end
17
16
  end
18
17
  ##
19
- # The main attraction of the Smart class. Returns a ChunkyPNG::Image that is sorted according to the options provided. Will return nil if it encounters an errors.
18
+ # The main attraction of the Smart class. Returns a ChunkyPNG::Image that is sorted according to the options provided. Will raise any error that occurs.
20
19
  def self.smart(input, o={})
21
20
  startTime=Time.now
22
21
  defOptions={
@@ -36,7 +35,7 @@ module Pxlsrt
36
35
  :vertical => [false, true],
37
36
  :diagonal => [false, true],
38
37
  :smooth => [false, true],
39
- :method => ["sum-rgb", "red", "green", "blue", "sum-hsb", "hue", "saturation", "brightness", "uniqueness", "luma", "random", "cyan", "magenta", "yellow", "alpha", "sum-rgba", "sum-hsba"],
38
+ :method => Pxlsrt::Colors::METHODS,
40
39
  :verbose => [false, true],
41
40
  :absolute => [false, true],
42
41
  :threshold => [{:class => [Float, Fixnum]}],
@@ -54,17 +53,14 @@ module Pxlsrt
54
53
  else
55
54
  Pxlsrt::Helpers.error("File #{input} is not a valid PNG.") if options[:verbose]
56
55
  raise "Invalid PNG"
57
- return
58
56
  end
59
57
  else
60
58
  Pxlsrt::Helpers.error("File #{input} doesn't exist!") if options[:verbose]
61
59
  raise "File doesn't exist"
62
- return
63
60
  end
64
61
  elsif input.class!=String and input.class!=ChunkyPNG::Image
65
62
  Pxlsrt::Helpers.error("Input is not a filename or ChunkyPNG::Image") if options[:verbose]
66
63
  raise "Invalid input (must be filename or ChunkyPNG::Image)"
67
- return
68
64
  end
69
65
  Pxlsrt::Helpers.verbose("Smart mode.") if options[:verbose]
70
66
  png=Pxlsrt::Image.new(input)
@@ -88,7 +84,9 @@ module Pxlsrt
88
84
  else
89
85
  iterator = lines.keys
90
86
  end
91
- Pxlsrt::Helpers.verbose("Dividing and pixel sorting lines") if options[:verbose]
87
+ prr = 0
88
+ len = iterator.to_a.length
89
+ Pxlsrt::Helpers.progress("Dividing and pixel sorting lines", prr, len) if options[:verbose]
92
90
  for k in iterator
93
91
  line = lines[k]
94
92
  divisions = []
@@ -133,6 +131,8 @@ module Pxlsrt
133
131
  png.replaceDiagonal(k, newLine) if !options[:vertical]
134
132
  png.replaceRDiagonal(k, newLine) if options[:vertical]
135
133
  end
134
+ prr += 1
135
+ Pxlsrt::Helpers.progress("Dividing and pixel sorting lines", prr, len) if options[:verbose]
136
136
  end
137
137
  endTime=Time.now
138
138
  timeElapsed=endTime-startTime
@@ -148,7 +148,6 @@ module Pxlsrt
148
148
  else
149
149
  Pxlsrt::Helpers.error("Options specified do not follow the correct format.") if options[:verbose]
150
150
  raise "Bad options"
151
- return
152
151
  end
153
152
  end
154
153
  end
@@ -1,5 +1,5 @@
1
1
  ##
2
2
  # The main module, your best friend.
3
3
  module Pxlsrt
4
- VERSION = "1.6.3"
4
+ VERSION = "1.7.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pxlsrt
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.3
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - EVA-01
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-13 00:00:00.000000000 Z
11
+ date: 2014-12-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -80,6 +80,7 @@ files:
80
80
  - lib/pxlsrt/colors.rb
81
81
  - lib/pxlsrt/helpers.rb
82
82
  - lib/pxlsrt/image.rb
83
+ - lib/pxlsrt/kim.rb
83
84
  - lib/pxlsrt/lines.rb
84
85
  - lib/pxlsrt/smart.rb
85
86
  - lib/pxlsrt/version.rb