pxlsrt 1.7.1 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d5307d37f9c289e44ebcef491140425fb87cc323
4
- data.tar.gz: 81efa6032e867501ed264d23c9c2d4947c9ea5d6
3
+ metadata.gz: fa77df27b6a2bcd94f0b1e23855baa5219e25f16
4
+ data.tar.gz: a3b71ee3d6f67fb348628bd917491db1193474bf
5
5
  SHA512:
6
- metadata.gz: 50ac440bddb401a3c52d563f2d99c8ad46dcbec066b09047faa4cbe0cafc8997521a42a6cb920c6191543773311795d62d4a8609db1cc746c34048f33f9a28ea
7
- data.tar.gz: 7f12f4968efc0759d276536eeea135efb4e02ef334fb2067d717c29ad641d44c13c300f80e4cc920538301f4d652ee06e3bac33b211375a8f53359f0d6706409
6
+ metadata.gz: 6dd4f1a8187e9ccf3bab9e7735a190f53491404caa40bc3ae776b53077b4193cb820a62ce6973151aa613bf0beed0b3d76193c69bdd53b66644445155197a72f
7
+ data.tar.gz: 43d0246a46cebfce1a22e4e817a65c8ead7fb5efd40f8daa4a0a5850ba054030b3f485701cc1191ec42bb846baf8a849e85eb8af99ef190534383eb98fdfa0ac
data/bin/pxlsrt CHANGED
@@ -59,7 +59,7 @@ class CLI < Thor
59
59
 
60
60
  option :method, :type => :string, :default => "brightness", :aliases => "-m", :enum => ["brightness", "white", "black"]
61
61
  option :value, :type => :numeric, :aliases => "-v"
62
- desc "kim INPUT OUTPUT [outputs]", "Uses Kim Asendorf's algorithm"
62
+ desc "kim INPUT OUTPUT [options]", "Uses Kim Asendorf's algorithm"
63
63
  def kim(input, output)
64
64
  k= {:trusted => true}
65
65
  for o in options.keys
@@ -67,6 +67,32 @@ class CLI < Thor
67
67
  end
68
68
  Pxlsrt::Kim.suite(input, output, k)
69
69
  end
70
+
71
+ option :reverse, :default => false, :aliases => "-r"
72
+ option :smooth, :type => :boolean, :default => false, :aliases => "-s"
73
+ option :method, :type => :string, :default => "sum-rgb", :banner => "[#{Pxlsrt::Colors::METHODS.join(" | ")}]", :aliases => "-m", :enum => Pxlsrt::Colors::METHODS
74
+ option :middle, :default => false, :aliases => "-M"
75
+ option :random, :default => false, :aliases => "-R"
76
+ option :distance, :default => 100, :aliases => "-d"
77
+ option :threshold, :default => 0.1, :aliases => "-t", :type => :numeric
78
+ desc "seed INPUT OUTPUT [options]", "Seed pixel sorting"
79
+ def seed(input, output)
80
+ k={:trusted=>true}
81
+ for o in options.keys
82
+ k[o.to_sym]=options[o]
83
+ end
84
+ if Pxlsrt::Helpers.isNumeric?(k[:random])
85
+ k[:random] = k[:random].to_i
86
+ else
87
+ k[:random] = false
88
+ end
89
+ if Pxlsrt::Helpers.isNumeric?(k[:distance])
90
+ k[:distance] = k[:distance].to_i
91
+ else
92
+ k[:distance] = false
93
+ end
94
+ Pxlsrt::Seed.suite(input, output, k)
95
+ end
70
96
  end
71
97
 
72
98
  CLI.start(ARGV)
@@ -0,0 +1,209 @@
1
+ require 'oily_png'
2
+
3
+ module Pxlsrt
4
+ ##
5
+ # Plant seeds, have them spiral out and sort.
6
+ class Seed
7
+ ##
8
+ # Uses Pxlsrt::Seed.seed to input and output from one method.
9
+ def self.suite(inputFileName, outputFileName, o={})
10
+ kml = Pxlsrt::Seed.seed(inputFileName, o)
11
+ if Pxlsrt::Helpers.contented(kml)
12
+ kml.save(outputFileName)
13
+ end
14
+ end
15
+ ##
16
+ # The main attraction of the Seed class. Returns a ChunkyPNG::Image that is sorted according to the options provided. Will raise any error that occurs.
17
+ def self.seed(input, o = {})
18
+ startTime = Time.now
19
+ defOptions = {
20
+ :reverse => false,
21
+ :smooth => false,
22
+ :method => "sum-rgb",
23
+ :verbose => false,
24
+ :trusted => false,
25
+ :middle => false,
26
+ :random => false,
27
+ :distance => 100,
28
+ :threshold => 0.1
29
+ }
30
+ defRules = {
31
+ :reverse => :anything,
32
+ :smooth => [false, true],
33
+ :method => Pxlsrt::Colors::METHODS,
34
+ :verbose => [false, true],
35
+ :trusted => [false, true],
36
+ :middle => :anything,
37
+ :random => [false, {:class => [Fixnum]}],
38
+ :distance => [false, {:class => [Fixnum]}],
39
+ :threshold => [{:class => [Float, Fixnum]}]
40
+ }
41
+ options = defOptions.merge(o)
42
+ if o.length == 0 or options[:trusted] == true or (options[:trusted] == false and o.length != 0 and Pxlsrt::Helpers.checkOptions(options, defRules) != false)
43
+ if input.class == String
44
+ Pxlsrt::Helpers.verbose("Getting image from file...") if options[:verbose]
45
+ if File.file?(input)
46
+ if Pxlsrt::Colors.isPNG?(input)
47
+ input = ChunkyPNG::Image.from_file(input)
48
+ else
49
+ Pxlsrt::Helpers.error("File #{input} is not a valid PNG.") if options[:verbose]
50
+ raise "Invalid PNG"
51
+ end
52
+ else
53
+ Pxlsrt::Helpers.error("File #{input} doesn't exist!") if options[:verbose]
54
+ raise "File doesn't exit"
55
+ end
56
+ elsif input.class != String and input.class != ChunkyPNG::Image
57
+ Pxlsrt::Helpers.error("Input is not a filename or ChunkyPNG::Image") if options[:verbose]
58
+ raise "Invalid input (must be filename or ChunkyPNG::Image)"
59
+ end
60
+ Pxlsrt::Helpers.verbose("Seed mode.") if options[:verbose]
61
+ Pxlsrt::Helpers.verbose("Creating Pxlsrt::Image object") if options[:verbose]
62
+ png = Pxlsrt::Image.new(input)
63
+ traversed = [false] * (png.getWidth * png.getHeight)
64
+ count = 0
65
+ seeds = []
66
+ if options[:random] != false
67
+ Pxlsrt::Helpers.progress("Planting seeds", 0, options[:random]) if options[:verbose]
68
+ for s in (0...options[:random])
69
+ x = (0...png.getWidth).to_a.sample
70
+ y = (0...png.getHeight).to_a.sample
71
+ seeds.push({
72
+ :spiral => Pxlsrt::Spiral.new(x, y),
73
+ :pixels => [png[x, y]],
74
+ :xy => [{:x => x, :y=>y}],
75
+ :placed => true,
76
+ :retired => false,
77
+ :anchor => {
78
+ :x => x,
79
+ :y => y
80
+ }
81
+ })
82
+ Pxlsrt::Helpers.progress("Planting seeds", s + 1, options[:random]) if options[:verbose]
83
+ end
84
+ else
85
+ Pxlsrt::Helpers.progress("Planting seeds", 0, png.getWidth * png.getHeight) if options[:verbose]
86
+ kernel = [[-1, -1, -1], [-1, 9, -1], [-1, -1, -1]]
87
+ i = (png.getWidth + png.getHeight - 2) * 2
88
+ for y in (1...(png.getHeight - 1))
89
+ for x in (1...(png.getWidth - 1))
90
+ sum = 0
91
+ for ky in ((-1)..1)
92
+ for kx in ((-1)..1)
93
+ sum += kernel[ky + 1][kx + 1] * (ChunkyPNG::Color.r(png[x + kx, y + ky]))
94
+ end
95
+ end
96
+ if sum < options[:threshold]
97
+ seeds.push({
98
+ :spiral => Pxlsrt::Spiral.new(x, y),
99
+ :pixels => [png[x, y]],
100
+ :xy => [{:x => x, :y=>y}],
101
+ :placed => true,
102
+ :retired => false,
103
+ :anchor => {
104
+ :x => x,
105
+ :y => y
106
+ }
107
+ })
108
+ end
109
+ i += 1
110
+ Pxlsrt::Helpers.progress("Planting seeds", i, png.getWidth * png.getHeight) if options[:verbose]
111
+ end
112
+ end
113
+ if options[:distance] != false
114
+ Pxlsrt::Helpers.progress("Removing seed clusters", 0, seeds.length) if options[:verbose]
115
+ results = []
116
+ i = 0
117
+ for current in seeds
118
+ add = true
119
+ for other in results
120
+ d = Math.sqrt((current[:anchor][:x] - other[:anchor][:x]) ** 2 + (current[:anchor][:y] - other[:anchor][:y]) ** 2)
121
+ add = false if d > 0 and d < options[:distance]
122
+ end
123
+ if add
124
+ results.push(current)
125
+ end
126
+ i += 1
127
+ Pxlsrt::Helpers.progress("Removing seed clusters", i, seeds.length) if options[:verbose]
128
+ end
129
+ seeds = results
130
+ end
131
+ end
132
+ for r in (0...seeds.length)
133
+ traversed[seeds[r][:anchor][:x] + seeds[r][:anchor][:y] * png.getWidth] = r
134
+ count += 1
135
+ end
136
+ Pxlsrt::Helpers.verbose("Planted #{seeds.length} seeds") if options[:verbose]
137
+ step = 0
138
+ Pxlsrt::Helpers.progress("Watch them grow!", count, traversed.length) if options[:verbose]
139
+ while count < traversed.length and seeds.length != 0
140
+ r = 0
141
+ retired = []
142
+ for seed in seeds
143
+ if !seed[:retired]
144
+ n = seed[:spiral].next
145
+ if n[:x] >= 0 and n[:y] >= 0 and n[:x] < png.getWidth and n[:y] < png.getHeight and !traversed[n[:x] + n[:y] * png.getWidth]
146
+ seed[:pixels].push(png[n[:x], n[:y]])
147
+ traversed[n[:x] + n[:y] * png.getWidth] = r
148
+ seed[:xy].push(n)
149
+ seed[:placed] = true
150
+ count += 1
151
+ else
152
+ if seed[:placed] == true
153
+ seed[:placed] = {
154
+ :count => 1,
155
+ :direction => seed[:spiral].direction,
156
+ :cycle => seed[:spiral].cycles
157
+ }
158
+ case seed[:placed][:direction]
159
+ when "up", "down"
160
+ seed[:placed][:value] = seed[:spiral].pos[:y]
161
+ seed[:placed][:valueS] = :y
162
+ when "left", "right"
163
+ seed[:placed][:value] = seed[:spiral].pos[:x]
164
+ seed[:placed][:valueS] = :x
165
+ end
166
+ else
167
+ seed[:placed][:count] += 1
168
+ if seed[:spiral].cycles != seed[:placed][:cycle] and seed[:placed][:direction] == seed[:spiral].direction and seed[:placed][:value] == seed[:spiral].pos[seed[:placed][:valueS]]
169
+ seed[:retired] = true
170
+ end
171
+ end
172
+ end
173
+ end
174
+ r += 1
175
+ end
176
+ step += 1
177
+ Pxlsrt::Helpers.progress("Watch them grow!", count, traversed.length) if options[:verbose]
178
+ end
179
+ Pxlsrt::Helpers.progress("Sort seeds and place pixels", 0, seeds.length) if options[:verbose]
180
+ r = 0
181
+ for seed in seeds
182
+ spiral = Pxlsrt::Spiral.new(seed[:anchor][:x], seed[:anchor][:y])
183
+ band = Pxlsrt::Helpers.handlePixelSort(seed[:pixels], options)
184
+ i = 0
185
+ for k in seed[:xy]
186
+ png[k[:x], k[:y]] = band[i]
187
+ i += 1
188
+ end
189
+ r += 1
190
+ Pxlsrt::Helpers.progress("Sort seeds and place pixels", r, seeds.length) if options[:verbose]
191
+ end
192
+ endTime=Time.now
193
+ timeElapsed=endTime-startTime
194
+ if timeElapsed < 60
195
+ Pxlsrt::Helpers.verbose("Took #{timeElapsed.round(4)} second#{ timeElapsed!=1.0 ? "s" : "" }.") if options[:verbose]
196
+ else
197
+ minutes=(timeElapsed/60).floor
198
+ seconds=(timeElapsed % 60).round(4)
199
+ Pxlsrt::Helpers.verbose("Took #{minutes} minute#{ minutes!=1 ? "s" : "" } and #{seconds} second#{ seconds!=1.0 ? "s" : "" }.") if options[:verbose]
200
+ end
201
+ Pxlsrt::Helpers.verbose("Returning ChunkyPNG::Image...") if options[:verbose]
202
+ return png.returnModified
203
+ else
204
+ Pxlsrt::Helpers.error("Options specified do not follow the correct format.") if options[:verbose]
205
+ raise "Bad options"
206
+ end
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,84 @@
1
+ module Pxlsrt
2
+ ##
3
+ # Spiral iteration.
4
+ class Spiral
5
+ def initialize(x, y)
6
+ @x = x
7
+ @y = y
8
+ @direction = "up"
9
+ @step = 1
10
+ @at = 0
11
+ @count = 0
12
+ @cycles = -1
13
+ end
14
+ ##
15
+ # Return current x value.
16
+ def x
17
+ return @x
18
+ end
19
+ ##
20
+ # Return current y value.
21
+ def y
22
+ return @y
23
+ end
24
+ ##
25
+ # Return current direction.
26
+ def direction
27
+ return @direction
28
+ end
29
+ ##
30
+ # Return amount iterated.
31
+ def count
32
+ return @count
33
+ end
34
+ ##
35
+ # Return cycles gone through completely.
36
+ def cycles
37
+ return @cycles
38
+ end
39
+ ##
40
+ # Return current position.
41
+ def pos
42
+ return {:x => @x, :y => @y}
43
+ end
44
+ ##
45
+ # Goes to next position. Returns position.
46
+ def next
47
+ case @direction
48
+ when "left"
49
+ @x -= 1
50
+ @at += 1
51
+ if @at == @step
52
+ @direction = "down"
53
+ @at = 0
54
+ @step += 1
55
+ end
56
+ when "down"
57
+ @y += 1
58
+ @at += 1
59
+ if @at == @step
60
+ @direction = "right"
61
+ @at = 0
62
+ end
63
+ when "right"
64
+ @x += 1
65
+ @at += 1
66
+ if @at == @step
67
+ @direction = "up"
68
+ @at = 0
69
+ @step += 1
70
+ end
71
+ when "up"
72
+ @cycles += 1 if @at == 0
73
+ @y -= 1
74
+ @at += 1
75
+ if @at == @step
76
+ @direction = "left"
77
+ @at = 0
78
+ end
79
+ end
80
+ @count += 1
81
+ return pos
82
+ end
83
+ end
84
+ end
@@ -1,5 +1,5 @@
1
1
  ##
2
2
  # The main module, your best friend.
3
3
  module Pxlsrt
4
- VERSION = "1.7.1"
4
+ VERSION = "1.8.0"
5
5
  end
data/lib/pxlsrt.rb CHANGED
@@ -5,4 +5,6 @@ require "pxlsrt/image"
5
5
  require "pxlsrt/colors"
6
6
  require "pxlsrt/brute"
7
7
  require "pxlsrt/smart"
8
- require "pxlsrt/kim"
8
+ require "pxlsrt/kim"
9
+ require "pxlsrt/spiral"
10
+ require "pxlsrt/seed"
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.7.1
4
+ version: 1.8.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-18 00:00:00.000000000 Z
11
+ date: 2014-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -82,7 +82,9 @@ files:
82
82
  - lib/pxlsrt/image.rb
83
83
  - lib/pxlsrt/kim.rb
84
84
  - lib/pxlsrt/lines.rb
85
+ - lib/pxlsrt/seed.rb
85
86
  - lib/pxlsrt/smart.rb
87
+ - lib/pxlsrt/spiral.rb
86
88
  - lib/pxlsrt/version.rb
87
89
  homepage: https://github.com/EVA-01/pxlsrt
88
90
  licenses: