pxlsrt 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2c2b3280ae7ad02daa4da266d7da0754a3d7723b
4
+ data.tar.gz: 626ec7cf24c9c746e2cdc39f65acd300e2485330
5
+ SHA512:
6
+ metadata.gz: 0e813eab6fb0931f8448cdc4c389c44fdc0cf958b32304ac8da870be94b5dd5422a925f1d72327b9c629b825eb41d31b6b88aa8d4f09e55c4d45d1a545880127
7
+ data.tar.gz: 77cb11792128cd2dfd458f76fa8f7adc0dbf1f0fed6bddd679a56bdfa5d8a81e93bb207e3f74a316c8b838052ee07c83d530d04a0bd89270dbc282a6de337cb7
data/bin/pxlsrt ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'pxlsrt'
5
+ require 'thor'
6
+
7
+ class PXLSRT < Thor
8
+ class_option :reverse, :type => :string, :default => "no", :banner => "[no | reverse | either]", :aliases => "-r", :enum => ["no", "reverse", "either"]
9
+ class_option :vertical, :type => :boolean, :default => false, :aliases => "-v"
10
+ class_option :diagonal, :type => :boolean, :default => false, :aliases => "-d"
11
+ class_option :smooth, :type => :boolean, :default => false, :aliases => "-s"
12
+ class_option :method, :type => :string, :default => "sum-rgb", :banner => "[sum-rgb | red | green | blue | sum-hsb | hue | saturation | brightness | uniqueness | luma | random]", :aliases => "-m", :enum => ["sum-rgb", "red", "green", "blue", "sum-hsb", "hue", "saturation", "brightness", "uniqueness", "luma", "random"]
13
+ class_option :diagonal, :type => :boolean, :default => false, :aliases => "-d"
14
+ class_option :verbose, :type => :boolean, :default => false, :aliases => "-V"
15
+
16
+ option :min, :type => :numeric, :default => Float::INFINITY, :banner => "MINIMUM BANDWIDTH"
17
+ option :max, :type => :numeric, :default => Float::INFINITY, :banner => "MAXIMUM BANDWIDTH"
18
+ desc "brute INPUT OUTPUT [options]", "Brute pixel sorting"
19
+ def brute(input, output)
20
+ k={}
21
+ for o in options.keys
22
+ k[o.to_sym]=options[o]
23
+ end
24
+ Pxlsrt::Brute.suite(input, output, true, k)
25
+ end
26
+
27
+ option :absolute, :type => :boolean, :default => false, :aliases => "-a", :banner => "ABSOLUTE EDGE FINDING"
28
+ option :threshold, :type => :numeric, :default => 20, :aliases => "-t"
29
+ option :edge, :type => :numeric, :default => 2, :aliases => "-e", :banner => "EDGE BUFFERING"
30
+ desc "smart INPUT OUTPUT [options]", "Smart pixel sorting"
31
+ def smart(input, output)
32
+ k={}
33
+ for o in options.keys
34
+ k[o.to_sym]=options[o]
35
+ end
36
+ Pxlsrt::Smart.suite(input, output, true, k)
37
+ end
38
+ end
39
+
40
+ PXLSRT.start(ARGV)
@@ -0,0 +1,137 @@
1
+ require 'rubygems'
2
+ require 'oily_png'
3
+
4
+ module Pxlsrt
5
+ class Brute
6
+ def self.suite(inputFileName, outputFileName, trusted, o={})
7
+ kml=Pxlsrt::Brute.brute(inputFileName, trusted, o)
8
+ if Pxlsrt::Helpers.contented(kml)
9
+ kml.save(outputFileName)
10
+ end
11
+ end
12
+ def self.brute(input, trusted, o={})
13
+ startTime=Time.now
14
+ defOptions={
15
+ :reverse => "no",
16
+ :vertical => false,
17
+ :diagonal => false,
18
+ :smooth => false,
19
+ :method => "sum-rgb",
20
+ :verbose => false,
21
+ :min => Float::INFINITY,
22
+ :max => Float::INFINITY
23
+ }
24
+ defRules={
25
+ :reverse => ["no", "reverse", "either"],
26
+ :vertical => [false, true],
27
+ :diagonal => [false, true],
28
+ :smooth => [false, true],
29
+ :method => ["sum-rgb", "red", "green", "blue", "sum-hsb", "hue", "saturation", "brightness", "uniqueness", "luma", "random"],
30
+ :verbose => [false, true],
31
+ :min => [Float::INFINITY, {:class => [Fixnum]}],
32
+ :max => [Float::INFINITY, {:class => [Fixnum]}]
33
+ }
34
+ options=defOptions.merge(o)
35
+ if o.length==0 or trusted==true or (trusted==false and o.length!=0 and Pxlsrt::Helpers.checkOptions(options, defRules)!=false)
36
+ Pxlsrt::Helpers.verbose("Options are all good.") if options[:verbose]
37
+ if input.class==String
38
+ Pxlsrt::Helpers.verbose("Getting image from file...") if options[:verbose]
39
+ input=ChunkyPNG::Image.from_file(input)
40
+ elsif input.class!=String and input.class!=ChunkyPNG::Image
41
+ Pxlsrt::Helpers.error("Input is not a filename or ChunkyPNG::Image") if options[:verbose]
42
+ return
43
+ end
44
+ Pxlsrt::Helpers.verbose("Brute mode.") if options[:verbose]
45
+ case options[:reverse].downcase
46
+ when "reverse"
47
+ nre=1
48
+ when "either"
49
+ nre=-1
50
+ else
51
+ nre=0
52
+ end
53
+ png=input
54
+ w=png.dimension.width
55
+ h=png.dimension.height
56
+ sorted=ChunkyPNG::Image.new(w, h, ChunkyPNG::Color::TRANSPARENT)
57
+ Pxlsrt::Helpers.verbose("Retrieving RGB values of pixels...") if options[:verbose]
58
+ kml=[]
59
+ for xy in 0..(w*h-1)
60
+ kml.push(Pxlsrt::Colors.getRGB(png[xy % w,(xy/w).floor]))
61
+ end
62
+ if options[:vertical]==true
63
+ Pxlsrt::Helpers.verbose("Rotating image for vertical mode...") if options[:verbose]
64
+ kml=Pxlsrt::Colors.rotateImage(kml, w, h, 3)
65
+ w,h=h,w
66
+ end
67
+ toImage=[]
68
+ if !options[:diagonal]
69
+ Pxlsrt::Helpers.verbose("Pixel sorting using method '#{options[:method]}'...") if options[:verbose]
70
+ for m in Pxlsrt::Colors.imageRGBLines(kml, w)
71
+ sliceRanges=Pxlsrt::Colors.randomSlices(m, options[:min], options[:max])
72
+ newInTown=[]
73
+ if options[:smooth]!=true
74
+ for ranger in sliceRanges
75
+ newInTown.concat(Pxlsrt::Colors.pixelSort(m[ranger[0]..ranger[1]], options[:method].downcase, nre))
76
+ end
77
+ else
78
+ for ranger in sliceRanges
79
+ k=(m[ranger[0]..ranger[1]]).group_by { |x| x }
80
+ g=Pxlsrt::Colors.pixelSort(k.keys, options[:method].downcase, nre)
81
+ j=g.map { |x| k[x] }.flatten(1)
82
+ newInTown.concat(j)
83
+ end
84
+ end
85
+ toImage.concat(newInTown)
86
+ end
87
+ else
88
+ Pxlsrt::Helpers.verbose("Determining diagonals...") if options[:verbose]
89
+ dia=Pxlsrt::Colors.getDiagonals(kml,w,h)
90
+ Pxlsrt::Helpers.verbose("Pixel sorting using method '#{options[:method]}'...") if options[:verbose]
91
+ for m in dia.keys
92
+ sliceRanges=Pxlsrt::Colors.randomSlices(dia[m], options[:min], options[:max])
93
+ newInTown=[]
94
+ if options[:smooth]!=true
95
+ for ranger in sliceRanges
96
+ newInTown.concat(Pxlsrt::Colors.pixelSort(dia[m][ranger[0]..ranger[1]], options[:method].downcase, nre))
97
+ end
98
+ else
99
+ for ranger in sliceRanges
100
+ k=(dia[m][ranger[0]..ranger[1]]).group_by { |x| x }
101
+ g=Pxlsrt::Colors.pixelSort(k.keys, options[:method].downcase, nre)
102
+ j=g.map { |x| k[x] }.flatten(1)
103
+ newInTown.concat(j)
104
+ end
105
+ end
106
+ dia[m]=newInTown
107
+ end
108
+ Pxlsrt::Helpers.verbose("Setting diagonals back to standard lines...") if options[:verbose]
109
+ toImage=Pxlsrt::Colors.fromDiagonals(dia,w)
110
+ end
111
+ if options[:vertical]==true
112
+ Pxlsrt::Helpers.verbose("Rotating back (because of vertical mode).") if options[:verbose]
113
+ toImage=Pxlsrt::Colors.rotateImage(toImage, w,h,1)
114
+ w,h=h,w
115
+ end
116
+ Pxlsrt::Helpers.verbose("Giving pixels new RGB values...") if options[:verbose]
117
+ for xy in 0..(w*h-1)
118
+ sorted[xy % w, (xy/w).floor]=Pxlsrt::Colors.arrayToRGB(toImage[xy])
119
+ end
120
+ endTime=Time.now
121
+ timeElapsed=endTime-startTime
122
+ if timeElapsed < 60
123
+ Pxlsrt::Helpers.verbose("Took #{timeElapsed.round(4)} second#{ timeElapsed!=1.0 ? "s" : "" }.") if options[:verbose]
124
+ else
125
+ minutes=(timeElapsed/60).floor
126
+ seconds=(timeElapsed % 60).round(4)
127
+ Pxlsrt::Helpers.verbose("Took #{minutes} minute#{ minutes!=1 ? "s" : "" } and #{seconds} second#{ seconds!=1.0 ? "s" : "" }.") if options[:verbose]
128
+ end
129
+ Pxlsrt::Helpers.verbose("Returning ChunkyPNG::Image...") if options[:verbose]
130
+ return sorted
131
+ else
132
+ Pxlsrt::Helpers.error("Options specified do not follow the correct format.") if options[:verbose]
133
+ return
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,183 @@
1
+ require "oily_png"
2
+
3
+ module Pxlsrt
4
+ class Colors
5
+ def self.getRGB(pxl)
6
+ return [ChunkyPNG::Color.r(pxl), ChunkyPNG::Color.g(pxl), ChunkyPNG::Color.b(pxl)]
7
+ end
8
+ def self.rotateImage(what, width, height, a)
9
+ nu=[]
10
+ case a
11
+ when 0, 360, 4
12
+ nu=what
13
+ when 1, 90
14
+ for xy in 0..(what.length-1)
15
+ nu[((height-1)-(xy/width).floor)+(xy % width)*height]=what[xy]
16
+ end
17
+ when 2, 180
18
+ nu=what.reverse
19
+ when 3, 270
20
+ for xy in 0..(what.length-1)
21
+ nu[(xy/width).floor+((width-1)-(xy % width))*height]=what[xy]
22
+ end
23
+ end
24
+ return nu
25
+ end
26
+ def self.imageRGBLines(image, width)
27
+ return image.each_slice(width).to_a
28
+ end
29
+ def self.randomSlices(arr, minLength, maxLength)
30
+ len=arr.length-1
31
+ if len!=0
32
+ min=[minLength, maxLength].min
33
+ max=[maxLength, minLength].max
34
+ if min > len
35
+ min=len
36
+ end
37
+ if max > len
38
+ max=len
39
+ end
40
+ nu=[[0, rand(min..max)]]
41
+ last=nu.first[1]
42
+ sorting=true
43
+ while sorting do
44
+ if (len-last) <= max
45
+ nu.push([last+1, len])
46
+ sorting=false
47
+ else
48
+ nu.push([last+1, last+1+rand(min..max)])
49
+ last=nu.last[1]
50
+ end
51
+ end
52
+ else
53
+ nu=[[0,0]]
54
+ end
55
+ return nu
56
+ end
57
+ def self.pxldex(pxl)
58
+ return pxl[0]+pxl[1]+pxl[2]
59
+ end
60
+ def self.rgb2hsb(rgb)
61
+ r = rgb[0] / 255.0
62
+ g = rgb[1] / 255.0
63
+ b = rgb[2] / 255.0
64
+ max = [r, g, b].max
65
+ min = [r, g, b].min
66
+ delta = max - min
67
+ v = max * 100
68
+ if (max != 0.0)
69
+ s = delta / max *100
70
+ else
71
+ s = 0.0
72
+ end
73
+ if (s == 0.0)
74
+ h = 0.0
75
+ else
76
+ if (r == max)
77
+ h = (g - b) / delta
78
+ elsif (g == max)
79
+ h = 2 + (b - r) / delta
80
+ elsif (b == max)
81
+ h = 4 + (r - g) / delta
82
+ end
83
+ h *= 60.0
84
+ if (h < 0)
85
+ h += 360.0
86
+ end
87
+ end
88
+ return [h,s,v]
89
+ end
90
+ def self.colorAverage(ca)
91
+ if ca.length==1
92
+ return ca.first
93
+ end
94
+ r=((ca.collect { |c| c[0] }).inject{ |sum, el| sum+el }).to_f / ca.size
95
+ g=((ca.collect { |c| c[1] }).inject{ |sum, el| sum+el }).to_f / ca.size
96
+ b=((ca.collect { |c| c[2] }).inject{ |sum, el| sum+el }).to_f / ca.size
97
+ return [r,g,b]
98
+ end
99
+ def self.colorDistance(c1,c2)
100
+ return Math.sqrt((c1[0]-c2[0])**2+(c1[1]-c2[1])**2+(c1[2]-c2[2])**2)
101
+ end
102
+ def self.colorUniqueness(c, ca)
103
+ return Pxlsrt::Colors.colorDistance(c, Pxlsrt::Colors.colorAverage(ca))
104
+ end
105
+ def self.pixelSort(list, how, reverse)
106
+ mhm=[]
107
+ case how.downcase
108
+ when "sum-rgb"
109
+ mhm= list.sort_by { |c| Pxlsrt::Colors.pxldex(c) }
110
+ when "red"
111
+ mhm= list.sort_by { |c| c[0] }
112
+ when "green"
113
+ mhm= list.sort_by { |c| c[1] }
114
+ when "blue"
115
+ mhm= list.sort_by { |c| c[2] }
116
+ when "hue"
117
+ mhm= list.sort_by { |c| Pxlsrt::Colors.rgb2hsb(c)[0] }
118
+ when "saturation"
119
+ mhm= list.sort_by { |c| Pxlsrt::Colors.rgb2hsb(c)[1] }
120
+ when "brightness"
121
+ mhm= list.sort_by { |c| Pxlsrt::Colors.rgb2hsb(c)[2] }
122
+ when "sum-hsb"
123
+ mhm= list.sort_by { |c| k=Pxlsrt::Colors.rgb2hsb(c); k[0]*100/360+k[1]+k[2] }
124
+ when "uniqueness"
125
+ avg=Pxlsrt::Colors.colorAverage(list)
126
+ mhm=list.sort_by { |c| Pxlsrt::Colors.colorUniqueness(c, [avg]) }
127
+ when "luma"
128
+ mhm=list.sort_by { |c| Pxlsrt::Colors.pxldex([c[0]*0.2126, c[1]*0.7152, c[2]*0.0722]) }
129
+ when "random"
130
+ mhm=list.shuffle
131
+ else
132
+ mhm= list.sort_by { |c| Pxlsrt::Colors.pxldex(c) }
133
+ end
134
+ if reverse == 0
135
+ return mhm
136
+ elsif reverse == 1
137
+ return mhm.reverse
138
+ else
139
+ return rand(0..1)==0 ? mhm : mhm.reverse
140
+ end
141
+ end
142
+ def self.getDiagonals(array, width, height)
143
+ dias={}
144
+ for x in (1-height)..(width-1)
145
+ z=[]
146
+ for y in 0..(height-1)
147
+ if (x+(width+1)*y).between?(width*y, (width*(y+1)-1))
148
+ z.push(array[(x+(width+1)*y)])
149
+ end
150
+ end
151
+ dias[x.to_s]=z
152
+ end
153
+ return dias
154
+ end
155
+ def self.fromDiagonals(obj, width)
156
+ ell=[]
157
+ for k in obj.keys
158
+ r=k.to_i
159
+ n=r < 0
160
+ if n
161
+ x=0
162
+ y=r.abs
163
+ else
164
+ x=r
165
+ y=0
166
+ end
167
+ ell[x+y*width]=obj[k].first
168
+ for v in 1..(obj[k].length-1)
169
+ x+=1
170
+ y+=1
171
+ ell[x+y*width]=obj[k][v]
172
+ end
173
+ end
174
+ return ell
175
+ end
176
+ def self.arrayToRGB(a)
177
+ return ChunkyPNG::Color.rgb(a[0], a[1], a[2])
178
+ end
179
+ def self.sobelate(i, x,y)
180
+ return ChunkyPNG::Color.to_grayscale_bytes(i[x,y]).first
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,49 @@
1
+ module Pxlsrt
2
+ class Helpers
3
+ def self.contented(c)
4
+ return (c.class!=NilClass and ((defined? c)!="nil") and ((/(\S)/.match("#{c}"))!=nil))
5
+ end
6
+ def self.red(what)
7
+ return "\e[31m#{what}\e[0m"
8
+ end
9
+ def self.cyan(what)
10
+ return "\e[36m#{what}\e[0m"
11
+ end
12
+ def self.checkOptions(options, rules)
13
+ match=true
14
+ for o in options.keys
15
+ o_match=false
16
+ if rules[o].class==Array
17
+ if rules[o].include?(options[o])
18
+ o_match=true
19
+ else
20
+ for r in 0...rules[o].length
21
+ if rules[o][r].class==Hash
22
+ for n in rules[o][r][:class]
23
+ if n==options[o].class
24
+ o_match=match
25
+ break
26
+ end
27
+ end
28
+ end
29
+ if o_match==true
30
+ break
31
+ end
32
+ end
33
+ end
34
+ end
35
+ match=(match and o_match)
36
+ if match==false
37
+ break
38
+ end
39
+ end
40
+ return match
41
+ end
42
+ def self.error(what)
43
+ puts "#{Pxlsrt::Helpers.red("pxlsrt")} #{what}"
44
+ end
45
+ def self.verbose(what)
46
+ puts "#{Pxlsrt::Helpers.cyan("pxlsrt")} #{what}"
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,219 @@
1
+ require 'rubygems'
2
+ require 'oily_png'
3
+ require 'json'
4
+ require 'pathname'
5
+ require 'fileutils'
6
+ require 'base64'
7
+
8
+ module Pxlsrt
9
+ class Smart
10
+ def self.suite(inputFileName, outputFileName, trusted, o={})
11
+ kml=Pxlsrt::Smart.smart(inputFileName, trusted, o)
12
+ if Pxlsrt::Helpers.contented(kml)
13
+ kml.save(outputFileName)
14
+ end
15
+ end
16
+ def self.smart(input, trusted, o={})
17
+ startTime=Time.now
18
+ defOptions={
19
+ :reverse => "no",
20
+ :vertical => false,
21
+ :diagonal => false,
22
+ :smooth => false,
23
+ :method => "sum-rgb",
24
+ :verbose => false,
25
+ :absolute => false,
26
+ :threshold => 20,
27
+ :edge => 2
28
+ }
29
+ defRules={
30
+ :reverse => ["no", "reverse", "either"],
31
+ :vertical => [false, true],
32
+ :diagonal => [false, true],
33
+ :smooth => [false, true],
34
+ :method => ["sum-rgb", "red", "green", "blue", "sum-hsb", "hue", "saturation", "brightness", "uniqueness", "luma", "random"],
35
+ :verbose => [false, true],
36
+ :absolute => [false, true],
37
+ :threshold => [{:class => [Float, Fixnum]}],
38
+ :edge => [{:class => [Fixnum]}]
39
+ }
40
+ options=defOptions.merge(o)
41
+ if o.length==0 or trusted==true or (trusted==false and o.length!=0 and Pxlsrt::Helpers.checkOptions(options, defRules)!=false)
42
+ Pxlsrt::Helpers.verbose("Options are all good.") if options[:verbose]
43
+ if input.class==String
44
+ Pxlsrt::Helpers.verbose("Getting image from file...") if options[:verbose]
45
+ input=ChunkyPNG::Image.from_file(input)
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
+ return
49
+ end
50
+ Pxlsrt::Helpers.verbose("Smart mode.") if options[:verbose]
51
+ case options[:reverse].downcase
52
+ when "reverse"
53
+ nre=1
54
+ when "either"
55
+ nre=-1
56
+ else
57
+ nre=0
58
+ end
59
+ img=input
60
+ w,h=img.width,img.height
61
+ sobel_x = [[-1,0,1], [-2,0,2], [-1,0,1]]
62
+ sobel_y = [[-1,-2,-1], [ 0, 0, 0], [ 1, 2, 1]]
63
+ edge = ChunkyPNG::Image.new(w, h, ChunkyPNG::Color::TRANSPARENT)
64
+ valued="start"
65
+ k=[]
66
+ Pxlsrt::Helpers.verbose("Getting Sobel values and colors for pixels...") if options[:verbose]
67
+ for xy in 0..(w*h-1)
68
+ x=xy % w
69
+ y=(xy/w).floor
70
+ if x!=0 and x!=(w-1) and y!=0 and y!=(h-1)
71
+ pixel_x=(sobel_x[0][0]*Pxlsrt::Colors.sobelate(img,x-1,y-1))+(sobel_x[0][1]*Pxlsrt::Colors.sobelate(img,x,y-1))+(sobel_x[0][2]*Pxlsrt::Colors.sobelate(img,x+1,y-1))+(sobel_x[1][0]*Pxlsrt::Colors.sobelate(img,x-1,y))+(sobel_x[1][1]*Pxlsrt::Colors.sobelate(img,x,y))+(sobel_x[1][2]*Pxlsrt::Colors.sobelate(img,x+1,y))+(sobel_x[2][0]*Pxlsrt::Colors.sobelate(img,x-1,y+1))+(sobel_x[2][1]*Pxlsrt::Colors.sobelate(img,x,y+1))+(sobel_x[2][2]*Pxlsrt::Colors.sobelate(img,x+1,y+1))
72
+ pixel_y=(sobel_y[0][0]*Pxlsrt::Colors.sobelate(img,x-1,y-1))+(sobel_y[0][1]*Pxlsrt::Colors.sobelate(img,x,y-1))+(sobel_y[0][2]*Pxlsrt::Colors.sobelate(img,x+1,y-1))+(sobel_y[1][0]*Pxlsrt::Colors.sobelate(img,x-1,y))+(sobel_y[1][1]*Pxlsrt::Colors.sobelate(img,x,y))+(sobel_y[1][2]*Pxlsrt::Colors.sobelate(img,x+1,y))+(sobel_y[2][0]*Pxlsrt::Colors.sobelate(img,x-1,y+1))+(sobel_y[2][1]*Pxlsrt::Colors.sobelate(img,x,y+1))+(sobel_y[2][2]*Pxlsrt::Colors.sobelate(img,x+1,y+1))
73
+ val = Math.sqrt(pixel_x * pixel_x + pixel_y * pixel_y).ceil
74
+ else
75
+ val = 2000000000
76
+ end
77
+ k.push({ "sobel" => val, "pixel" => [x, y], "color" => Pxlsrt::Colors.getRGB(img[x, y]) })
78
+ end
79
+ if options[:vertical]==true
80
+ Pxlsrt::Helpers.verbose("Rotating image for vertical mode...") if options[:verbose]
81
+ k=Pxlsrt::Colors.rotateImage(k,w,h,3)
82
+ w,h=h,w
83
+ end
84
+ if !options[:diagonal]
85
+ lines=Pxlsrt::Colors.imageRGBLines(k, w)
86
+ Pxlsrt::Helpers.verbose("Determining bands with a#{options[:absolute] ? "n absolute" : " relative"} threshold of #{options[:threshold]}...") if options[:verbose]
87
+ bands=Array.new()
88
+ for j in lines
89
+ slicing=true
90
+ pixel=0
91
+ m=Array.new()
92
+ while slicing do
93
+ n=Array.new
94
+ if m.length > 1
95
+ while m.last.length < options[:edge]
96
+ if m.length > 1
97
+ m[-2].concat(m[-1])
98
+ m.pop
99
+ else
100
+ break
101
+ end
102
+ end
103
+ end
104
+ bandWorking=true
105
+ while bandWorking do
106
+ n.push(j[pixel]["color"])
107
+ if (options[:absolute] ? (j[pixel+1]["sobel"]) : (j[pixel+1]["sobel"]-j[pixel]["sobel"])) > options[:threshold]
108
+ bandWorking=false
109
+ end
110
+ if (pixel+1)==(j.length-1)
111
+ n.push(j[pixel+1]["color"])
112
+ slicing=false
113
+ bandWorking=false
114
+ end
115
+ pixel+=1
116
+ end
117
+ m.push(n)
118
+ end
119
+ bands.concat(m)
120
+ end
121
+ Pxlsrt::Helpers.verbose("Pixel sorting using method '#{options[:method]}'...") if options[:verbose]
122
+ image=[]
123
+ if options[:smooth]
124
+ for band in bands
125
+ u=band.group_by {|x| x}
126
+ image.concat(Pxlsrt::Colors.pixelSort(u.keys, options[:method], nre).map { |x| u[x] }.flatten(1))
127
+ end
128
+ else
129
+ for band in bands
130
+ image.concat(Pxlsrt::Colors.pixelSort(band, options[:method], nre))
131
+ end
132
+ end
133
+ else
134
+ Pxlsrt::Helpers.verbose("Determining diagonals...") if options[:verbose]
135
+ dia=Pxlsrt::Colors.getDiagonals(k,w,h)
136
+ Pxlsrt::Helpers.verbose("Determining bands with a#{options[:absolute] ? "n absolute" : " relative"} threshold of #{options[:threshold]}...") if options[:verbose]
137
+ for j in dia.keys
138
+ bands=[]
139
+ if dia[j].length>1
140
+ slicing=true
141
+ pixel=0
142
+ m=Array.new()
143
+ while slicing do
144
+ n=Array.new
145
+ if m.length > 1
146
+ while m.last.length < options[:edge]
147
+ if m.length > 1
148
+ m[-2].concat(m[-1])
149
+ m.pop
150
+ else
151
+ break
152
+ end
153
+ end
154
+ end
155
+ bandWorking=true
156
+ while bandWorking do
157
+ n.push(dia[j][pixel]["color"])
158
+ if (options[:absolute] ? (dia[j][pixel+1]["sobel"]) : (dia[j][pixel+1]["sobel"]-dia[j][pixel]["sobel"])) > options[:threshold]
159
+ bandWorking=false
160
+ end
161
+ if (pixel+1)==(dia[j].length-1)
162
+ n.push(dia[j][pixel+1]["color"])
163
+ slicing=false
164
+ bandWorking=false
165
+ end
166
+ pixel+=1
167
+ end
168
+ m.push(n)
169
+ end
170
+ else
171
+ m=[[dia[j].first["color"]]]
172
+ end
173
+ dia[j]=bands.concat(m)
174
+ end
175
+ Pxlsrt::Helpers.verbose("Pixel sorting using method '#{options[:method]}'...") if options[:verbose]
176
+ for j in dia.keys
177
+ ell=[]
178
+ if options[:smooth]
179
+ for band in dia[j]
180
+ u=band.group_by {|x| x}
181
+ ell.concat(Pxlsrt::Colors.pixelSort(u.keys, options[:method], nre).map { |x| u[x] }.flatten(1))
182
+ end
183
+ else
184
+ for band in dia[j]
185
+ ell.concat(Pxlsrt::Colors.pixelSort(band, options[:method], nre))
186
+ end
187
+ end
188
+ dia[j]=ell
189
+ end
190
+ Pxlsrt::Helpers.verbose("Setting diagonals back to standard lines...") if options[:verbose]
191
+ image=Pxlsrt::Colors.fromDiagonals(dia,w)
192
+ end
193
+ if options[:vertical]==true
194
+ Pxlsrt::Helpers.verbose("Rotating back (because of vertical mode).") if options[:verbose]
195
+ image=Pxlsrt::Colors.rotateImage(image,w,h,1)
196
+ w,h=h,w
197
+ end
198
+ Pxlsrt::Helpers.verbose("Giving pixels new RGB values...") if options[:verbose]
199
+ for px in 0..(w*h-1)
200
+ edge[px % w, (px/w).floor]=Pxlsrt::Colors.arrayToRGB(image[px])
201
+ end
202
+ endTime=Time.now
203
+ timeElapsed=endTime-startTime
204
+ if timeElapsed < 60
205
+ Pxlsrt::Helpers.verbose("Took #{timeElapsed.round(4)} second#{ timeElapsed.round(4)!=1.0 ? "s" : "" }.") if options[:verbose]
206
+ else
207
+ minutes=(timeElapsed/60).floor
208
+ seconds=(timeElapsed % 60).round(4)
209
+ Pxlsrt::Helpers.verbose("Took #{minutes} minute#{ minutes!=1 ? "s" : "" } and #{seconds} second#{ seconds!=1.0 ? "s" : "" }.") if options[:verbose]
210
+ end
211
+ Pxlsrt::Helpers.verbose("Returning ChunkyPNG::Image...") if options[:verbose]
212
+ return edge
213
+ else
214
+ Pxlsrt::Helpers.error("Options specified do not follow the correct format.") if options[:verbose]
215
+ return
216
+ end
217
+ end
218
+ end
219
+ end
@@ -0,0 +1,3 @@
1
+ module Pxlsrt
2
+ VERSION = "1.0.0"
3
+ end
data/lib/pxlsrt.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "pxlsrt/version"
2
+ require "pxlsrt/colors"
3
+ require "pxlsrt/helpers"
4
+ require "pxlsrt/brute"
5
+ require "pxlsrt/smart"
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pxlsrt
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - EVA-01
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.2'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: oily_png
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 1.1.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.1.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: thor
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.18'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.18'
69
+ description: Pixel sort PNG files with ease!
70
+ email:
71
+ - j.bruno.che@gmail.com
72
+ executables:
73
+ - pxlsrt
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - bin/pxlsrt
78
+ - lib/pxlsrt.rb
79
+ - lib/pxlsrt/brute.rb
80
+ - lib/pxlsrt/colors.rb
81
+ - lib/pxlsrt/helpers.rb
82
+ - lib/pxlsrt/smart.rb
83
+ - lib/pxlsrt/version.rb
84
+ homepage: https://github.com/EVA-01/pxlsrt
85
+ licenses:
86
+ - MIT
87
+ metadata: {}
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 2.2.2
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: Pixel sort PNG files.
108
+ test_files: []