pxlsrt 1.5.1 → 1.6

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: b67067a23830e901ce06d35571c5e5435ce6cb3b
4
- data.tar.gz: 93809cf7e8cd9fc620008f1c28bab5b381e70079
3
+ metadata.gz: eddc063a560a8420871b095ee6e56c96d1b3b66b
4
+ data.tar.gz: dcfb8606b9c47d43402e6030a80d274b83d3a4e0
5
5
  SHA512:
6
- metadata.gz: 4b3fa27fd1981baeba1d480b1b6ecea8e8a8f58c75d218310e560e62f03efd4c83764bf1f8bc012f660f3c7ed885df06b6c39daef81ab3923f141691507fb281
7
- data.tar.gz: 0c26e6b7c66683d371dd4cb7a1c650c1a46a9050e2bbc90c09cafe6c28278c09a72d3ef0e3dc146680c7d1251b59cf10d4e0e4cd3ec8cf0d7d2caaa060f75b5f
6
+ metadata.gz: e4b768476d0bda214468c888b1357396d4c62bc5d60aa45546c8d283f73b1957a3e11112589ae689c6a67a2ec0ca37609b94c55b77d70f118949894fb976655c
7
+ data.tar.gz: 9afbf4b2e3515a51d95143d7d30e031788f7de39ade4870e98f17938b4026b5c9a687a840c493c58641669db04b7ff6dad3b0f045ed5f07fbe3baf513b593111
data/bin/pxlsrt CHANGED
@@ -39,13 +39,11 @@ class CLI < Thor
39
39
 
40
40
  option :absolute, :type => :boolean, :default => false, :aliases => "-a", :banner => "ABSOLUTE EDGE FINDING"
41
41
  option :threshold, :type => :numeric, :default => 20, :aliases => "-t"
42
- option :edge, :type => :numeric, :default => 2, :aliases => "-e", :banner => "EDGE BUFFERING"
43
42
  desc "smart INPUT OUTPUT [options]", "Smart pixel sorting"
44
43
  ##
45
44
  # Specific options:
46
45
  # * threshold - Number used in edge finding. Specifics explained under "absolute".
47
46
  # * absolute - Make edge finding absolute over relative. For example, define a range as a collection of values under the threshold. Relative edge finding is when the contrast of the next pixel is larger than the threshold.
48
- # * edge - Buffers edge.
49
47
  def smart(input, output)
50
48
  k={:trusted=>true}
51
49
  for o in options.keys
data/lib/pxlsrt/brute.rb CHANGED
@@ -63,80 +63,42 @@ module Pxlsrt
63
63
  return
64
64
  end
65
65
  Pxlsrt::Helpers.verbose("Brute mode.") if options[:verbose]
66
- case options[:reverse].downcase
67
- when "reverse"
68
- nre=1
69
- when "either"
70
- nre=-1
71
- else
72
- nre=0
73
- end
74
- png=input
75
- w=png.dimension.width
76
- h=png.dimension.height
77
- sorted=ChunkyPNG::Image.new(w, h, ChunkyPNG::Color::TRANSPARENT)
78
- Pxlsrt::Helpers.verbose("Retrieving RGB values of pixels...") if options[:verbose]
79
- kml=[]
80
- for xy in 0..(w*h-1)
81
- kml.push(Pxlsrt::Colors.getRGBA(png[xy % w,(xy/w).floor]))
66
+ Pxlsrt::Helpers.verbose("Creating Pxlsrt::Image object") if options[:verbose]
67
+ png=Pxlsrt::Image.new(input)
68
+ if !options[:vertical] and !options[:diagonal]
69
+ Pxlsrt::Helpers.verbose("Retrieving rows") if options[:verbose]
70
+ lines = png.horizontalLines
71
+ elsif options[:vertical] and !options[:diagonal]
72
+ Pxlsrt::Helpers.verbose("Retrieving columns") if options[:verbose]
73
+ lines = png.verticalLines
74
+ elsif !options[:vertical] and options[:diagonal]
75
+ Pxlsrt::Helpers.verbose("Retrieving diagonals") if options[:verbose]
76
+ lines = png.diagonalLines
77
+ elsif options[:vertical] and options[:diagonal]
78
+ Pxlsrt::Helpers.verbose("Retrieving diagonals") if options[:verbose]
79
+ lines = png.rDiagonalLines
82
80
  end
83
- if options[:vertical]==true
84
- Pxlsrt::Helpers.verbose("Rotating image for vertical mode...") if options[:verbose]
85
- kml=Pxlsrt::Lines.rotateImage(kml, w, h, 3)
86
- w,h=h,w
87
- end
88
- toImage=[]
89
81
  if !options[:diagonal]
90
- Pxlsrt::Helpers.verbose("Pixel sorting using method '#{options[:method]}'...") if options[:verbose]
91
- for m in Pxlsrt::Lines.imageRGBLines(kml, w)
92
- sliceRanges=Pxlsrt::Lines.randomSlices(m, options[:min], options[:max])
93
- newInTown=[]
94
- if options[:smooth]!=true
95
- for ranger in sliceRanges
96
- newInTown.concat(Pxlsrt::Lines.handleMiddlate(Pxlsrt::Colors.pixelSort(m[ranger[0]..ranger[1]], options[:method].downcase, nre), options[:middle]))
97
- end
98
- else
99
- for ranger in sliceRanges
100
- k=(m[ranger[0]..ranger[1]]).group_by { |x| x }
101
- g=Pxlsrt::Lines.handleMiddlate(Pxlsrt::Colors.pixelSort(k.keys, options[:method].downcase, nre), options[:middle])
102
- j=g.map { |x| k[x] }.flatten(1)
103
- newInTown.concat(j)
104
- end
105
- end
106
- toImage.concat(newInTown)
107
- end
82
+ iterator = 0...(lines.length)
108
83
  else
109
- Pxlsrt::Helpers.verbose("Determining diagonals...") if options[:verbose]
110
- dia=Pxlsrt::Lines.getDiagonals(kml,w,h)
111
- Pxlsrt::Helpers.verbose("Pixel sorting using method '#{options[:method]}'...") if options[:verbose]
112
- for m in dia.keys
113
- sliceRanges=Pxlsrt::Lines.randomSlices(dia[m], options[:min], options[:max])
114
- newInTown=[]
115
- if options[:smooth]!=true
116
- for ranger in sliceRanges
117
- newInTown.concat(Pxlsrt::Lines.handleMiddlate(Pxlsrt::Colors.pixelSort(dia[m][ranger[0]..ranger[1]], options[:method].downcase, nre), options[:middle]))
118
- end
119
- else
120
- for ranger in sliceRanges
121
- k=(dia[m][ranger[0]..ranger[1]]).group_by { |x| x }
122
- g=Pxlsrt::Lines.handleMiddlate(Pxlsrt::Colors.pixelSort(k.keys, options[:method].downcase, nre), options[:middle])
123
- j=g.map { |x| k[x] }.flatten(1)
124
- newInTown.concat(j)
125
- end
126
- end
127
- dia[m]=newInTown
128
- end
129
- Pxlsrt::Helpers.verbose("Setting diagonals back to standard lines...") if options[:verbose]
130
- toImage=Pxlsrt::Lines.fromDiagonals(dia,w)
131
- end
132
- if options[:vertical]==true
133
- Pxlsrt::Helpers.verbose("Rotating back (because of vertical mode).") if options[:verbose]
134
- toImage=Pxlsrt::Lines.rotateImage(toImage, w,h,1)
135
- w,h=h,w
84
+ iterator = lines.keys
136
85
  end
137
- Pxlsrt::Helpers.verbose("Giving pixels new RGB values...") if options[:verbose]
138
- for xy in 0..(w*h-1)
139
- sorted[xy % w, (xy/w).floor]=Pxlsrt::Colors.arrayToRGBA(toImage[xy])
86
+ Pxlsrt::Helpers.verbose("Dividing and pixel sorting lines") if options[:verbose]
87
+ for k in iterator
88
+ line = lines[k]
89
+ divisions = Pxlsrt::Lines.randomSlices(line.length,options[:min],options[:max])
90
+ newLine = []
91
+ for division in divisions
92
+ band = line[division[0]..division[1]]
93
+ newLine.concat(Pxlsrt::Helpers.handlePixelSort(band, options))
94
+ end
95
+ if !options[:diagonal]
96
+ png.replaceHorizontal(k, newLine) if !options[:vertical]
97
+ png.replaceVertical(k, newLine) if options[:vertical]
98
+ else
99
+ png.replaceDiagonal(k, newLine) if !options[:vertical]
100
+ png.replaceRDiagonal(k, newLine) if options[:vertical]
101
+ end
140
102
  end
141
103
  endTime=Time.now
142
104
  timeElapsed=endTime-startTime
@@ -148,7 +110,7 @@ module Pxlsrt
148
110
  Pxlsrt::Helpers.verbose("Took #{minutes} minute#{ minutes!=1 ? "s" : "" } and #{seconds} second#{ seconds!=1.0 ? "s" : "" }.") if options[:verbose]
149
111
  end
150
112
  Pxlsrt::Helpers.verbose("Returning ChunkyPNG::Image...") if options[:verbose]
151
- return sorted
113
+ return png.returnModified
152
114
  else
153
115
  Pxlsrt::Helpers.error("Options specified do not follow the correct format.") if options[:verbose]
154
116
  return
data/lib/pxlsrt/colors.rb CHANGED
@@ -48,25 +48,37 @@ module Pxlsrt
48
48
  end
49
49
  ##
50
50
  # Averages an array of RGB-like arrays.
51
- def self.colorAverage(ca)
51
+ def self.colorAverage(ca, chunky = false)
52
52
  if ca.length==1
53
53
  return ca.first
54
54
  end
55
- r=((ca.collect { |c| c[0] }).inject{ |sum, el| sum+el }).to_f / ca.size
56
- g=((ca.collect { |c| c[1] }).inject{ |sum, el| sum+el }).to_f / ca.size
57
- b=((ca.collect { |c| c[2] }).inject{ |sum, el| sum+el }).to_f / ca.size
58
- a=((ca.collect { |c| c[3] }).inject{ |sum, el| sum+el }).to_f / ca.size
59
- return [r,g,b,a]
55
+ if !chunky
56
+ r=((ca.collect { |c| c[0] }).inject{ |sum, el| sum+el }).to_f / ca.size
57
+ g=((ca.collect { |c| c[1] }).inject{ |sum, el| sum+el }).to_f / ca.size
58
+ b=((ca.collect { |c| c[2] }).inject{ |sum, el| sum+el }).to_f / ca.size
59
+ a=((ca.collect { |c| c[3] }).inject{ |sum, el| sum+el }).to_f / ca.size
60
+ return [r,g,b,a]
61
+ else
62
+ r=((ca.collect { |c| ChunkyPNG::Color.r(c) }).inject{ |sum, el| sum+el }).to_f / ca.size
63
+ g=((ca.collect { |c| ChunkyPNG::Color.g(c) }).inject{ |sum, el| sum+el }).to_f / ca.size
64
+ b=((ca.collect { |c| ChunkyPNG::Color.b(c) }).inject{ |sum, el| sum+el }).to_f / ca.size
65
+ a=((ca.collect { |c| ChunkyPNG::Color.a(c) }).inject{ |sum, el| sum+el }).to_f / ca.size
66
+ return ChunkyPNG::Color.rgba(r,g,b,a)
67
+ end
60
68
  end
61
69
  ##
62
70
  # Determines color distance from each other using the Pythagorean theorem.
63
- def self.colorDistance(c1,c2)
64
- return Math.sqrt((c1[0]-c2[0])**2+(c1[1]-c2[1])**2+(c1[2]-c2[2])**2+(c1[3]-c2[3])**2)
71
+ def self.colorDistance(c1,c2,chunky = false)
72
+ if !chunky
73
+ return Math.sqrt((c1[0]-c2[0])**2+(c1[1]-c2[1])**2+(c1[2]-c2[2])**2+(c1[3]-c2[3])**2)
74
+ else
75
+ 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)
76
+ end
65
77
  end
66
78
  ##
67
79
  # Uses a combination of color averaging and color distance to find how "unique" a color is.
68
- def self.colorUniqueness(c, ca)
69
- return Pxlsrt::Colors.colorDistance(c, Pxlsrt::Colors.colorAverage(ca))
80
+ def self.colorUniqueness(c, ca, chunky = false)
81
+ return Pxlsrt::Colors.colorDistance(c, Pxlsrt::Colors.colorAverage(ca, chunky), chunky)
70
82
  end
71
83
  ##
72
84
  # Sorts an array of colors based on a method.
@@ -92,42 +104,42 @@ module Pxlsrt
92
104
  mhm=[]
93
105
  case how.downcase
94
106
  when "sum-rgb"
95
- mhm= list.sort_by { |c| c[0]+c[1]+c[2] }
107
+ mhm= list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.g(c)+ChunkyPNG::Color.b(c) }
96
108
  when "sum-rgba"
97
- mhm=list.sort_by { |c| c[0]+c[1]+c[2]+c[3] }
109
+ mhm=list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.g(c)+ChunkyPNG::Color.b(c)+ChunkyPNG::Color.a(c) }
98
110
  when "red"
99
- mhm= list.sort_by { |c| c[0] }
111
+ mhm= list.sort_by { |c| ChunkyPNG::Color.r(c) }
100
112
  when "yellow"
101
- mhm=list.sort_by { |c| c[0]+c[1] }
113
+ mhm=list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.g(c) }
102
114
  when "green"
103
- mhm= list.sort_by { |c| c[1] }
115
+ mhm= list.sort_by { |c| ChunkyPNG::Color.g(c) }
104
116
  when "cyan"
105
- mhm=list.sort_by { |c| c[1]+c[2] }
117
+ mhm=list.sort_by { |c| ChunkyPNG::Color.g(c)+ChunkyPNG::Color.b(c) }
106
118
  when "blue"
107
- mhm= list.sort_by { |c| c[2] }
119
+ mhm= list.sort_by { |c| ChunkyPNG::Color.b(c) }
108
120
  when "magenta"
109
- mhm=list.sort_by { |c| c[0]+c[2] }
121
+ mhm=list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.b(c) }
110
122
  when "hue"
111
- mhm= list.sort_by { |c| Pxlsrt::Colors.rgb2hsb(c)[0] }
123
+ mhm= list.sort_by { |c| d = Pxlsrt::Colors.getRGBA(c); Pxlsrt::Colors.rgb2hsb(d)[0] }
112
124
  when "saturation"
113
- mhm= list.sort_by { |c| Pxlsrt::Colors.rgb2hsb(c)[1] }
125
+ mhm= list.sort_by { |c| d = Pxlsrt::Colors.getRGBA(c); Pxlsrt::Colors.rgb2hsb(d)[1] }
114
126
  when "brightness"
115
- mhm= list.sort_by { |c| Pxlsrt::Colors.rgb2hsb(c)[2] }
127
+ mhm= list.sort_by { |c| d = Pxlsrt::Colors.getRGBA(c); Pxlsrt::Colors.rgb2hsb(d)[2] }
116
128
  when "sum-hsb"
117
- mhm= list.sort_by { |c| k=Pxlsrt::Colors.rgb2hsb(c); k[0]*100.0/360+k[1]+k[2] }
129
+ mhm= list.sort_by { |c| d = Pxlsrt::Colors.getRGBA(c); k=Pxlsrt::Colors.rgb2hsb(d); k[0]*100.0/360+k[1]+k[2] }
118
130
  when "sum-hsba"
119
- mhm= list.sort_by { |c| k=Pxlsrt::Colors.rgb2hsb(c); k[0]*100.0/360+k[1]+k[2]+c[3]*100.0/255 }
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]+d.a*100.0/255 }
120
132
  when "uniqueness"
121
- avg=Pxlsrt::Colors.colorAverage(list)
122
- mhm=list.sort_by { |c| Pxlsrt::Colors.colorUniqueness(c, [avg]) }
133
+ avg=Pxlsrt::Colors.colorAverage(list, true)
134
+ mhm=list.sort_by { |c| Pxlsrt::Colors.colorUniqueness(c, [avg], true) }
123
135
  when "luma"
124
- mhm=list.sort_by { |c| c[0]*0.2126+c[1]*0.7152+c[2]*0.0722 }
136
+ mhm=list.sort_by { |c| ChunkyPNG::Color.r(c)*0.2126+ChunkyPNG::Color.g(c)*0.7152+ChunkyPNG::Color.b(c)*0.0722 }
125
137
  when "random"
126
138
  mhm=list.shuffle
127
139
  when "alpha"
128
- mhm=list.sort_by{ |c| c[3] }
140
+ mhm=list.sort_by{ |c| ChunkyPNG::Color.a(c) }
129
141
  else
130
- mhm= list.sort_by { |c| c[0]+c[1]+c[2] }
142
+ mhm= list.sort_by { |c| ChunkyPNG::Color.r(c)+ChunkyPNG::Color.g(c)+ChunkyPNG::Color.b(c) }
131
143
  end
132
144
  if reverse == 0
133
145
  return mhm
@@ -57,6 +57,30 @@ module Pxlsrt
57
57
  return match
58
58
  end
59
59
  ##
60
+ # Pixel sorting helper to eliminate repetition.
61
+ def self.handlePixelSort(band, o)
62
+ if o[:reverse].downcase == "reverse"
63
+ reverse = 1
64
+ elsif 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
+ ##
60
84
  # Prints an error message.
61
85
  def self.error(what)
62
86
  puts "#{Pxlsrt::Helpers.red("pxlsrt")} #{what}"
@@ -0,0 +1,172 @@
1
+ module Pxlsrt
2
+ ##
3
+ # Image class for handling ChunkyPNG images.
4
+ class Image
5
+ def initialize(png)
6
+ @original = png
7
+ @width = png.width
8
+ @height = png.height
9
+ @modified = png
10
+ end
11
+ ##
12
+ # Retrieve a multidimensional array consisting of the horizontal lines (row) of the image.
13
+ def horizontalLines
14
+ return (0...@height).inject([]) { | arr, row | arr << @modified.row(row) }
15
+ end
16
+ ##
17
+ # Replace a horizontal line (row) of the image.
18
+ def replaceHorizontal(y, arr)
19
+ @modified.replace_row!(y, arr)
20
+ return @modified
21
+ end
22
+ ##
23
+ # Retrieve the x and y coordinates of a pixel based on the multidimensional array created using the horizontalLines method.
24
+ def horizontalXY(horizontal, index)
25
+ return {
26
+ "x" => index.to_i,
27
+ "y" => horizontal.to_i
28
+ }
29
+ end
30
+ ##
31
+ # Retrieve a multidimensional array consisting of the vertical lines of the image.
32
+ def verticalLines
33
+ return (0...@width).inject([]) { | arr, column | arr << @modified.column(column) }
34
+ end
35
+ ##
36
+ # Replace a vertical line (column) of the image.
37
+ def replaceVertical(y, arr)
38
+ @modified.replace_column!(y, arr)
39
+ return @modified
40
+ end
41
+ ##
42
+ # Retrieve the x and y coordinates of a pixel based on the multidimensional array created using the verticalLines method.
43
+ def verticalXY(vertical, index)
44
+ return {
45
+ "x" => vertical.to_i,
46
+ "y" => index.to_i
47
+ }
48
+ end
49
+ ##
50
+ # Retrieve a hash consisting of the diagonal lines (top left to bottom right) of the image.
51
+ def diagonalLines
52
+ return Pxlsrt::Lines.getDiagonals(self.horizontalLines.flatten(1), @width, @height)
53
+ end
54
+ ##
55
+ # Retrieve a hash consisting of the diagonal lines (bottom left to top right) of the image.
56
+ def rDiagonalLines
57
+ return Pxlsrt::Lines.getDiagonals(self.horizontalLines.reverse.flatten(1).reverse, @width, @height)
58
+ end
59
+ ##
60
+ # Get the column and row based on the diagonal hash created using diagonalLines.
61
+ def diagonalColumnRow(d, i)
62
+ return {
63
+ "column" => ((d.to_i < 0) ? i : d.to_i + i).to_i,
64
+ "row" => ((d.to_i < 0) ? d.to_i.abs + i : i).to_i
65
+ }
66
+ end
67
+ ##
68
+ # Replace a diagonal line (top left to bottom right) of the image.
69
+ def replaceDiagonal(d, arr)
70
+ d = d.to_i
71
+ for i in 0...arr.length
72
+ xy = self.diagonalXY(d, i)
73
+ self[xy["x"], xy["y"]] = arr[i]
74
+ end
75
+ end
76
+ ##
77
+ # Replace a diagonal line (bottom left to top right) of the image.
78
+ def replaceRDiagonal(d, arr)
79
+ d = d.to_i
80
+ for i in 0...arr.length
81
+ xy = self.rDiagonalXY(d, i)
82
+ self[xy["x"], xy["y"]] = arr[i]
83
+ end
84
+ end
85
+ ##
86
+ # Retrieve the x and y coordinates of a pixel based on the hash created using the diagonalLines method and the column and row of the diagonalColumnRow method.
87
+ def diagonalXY(d, i)
88
+ cr = self.diagonalColumnRow(d, i)
89
+ return {
90
+ "x" => cr["column"],
91
+ "y" => cr["row"]
92
+ }
93
+ end
94
+ ##
95
+ # Retrieve the x and y coordinates of a pixel based on the hash created using the rDiagonalLines method and the column and row of the diagonalColumnRow method.
96
+ def rDiagonalXY(d, i)
97
+ cr = self.diagonalColumnRow(d, i)
98
+ return {
99
+ "x" => @width - 1 - cr["column"],
100
+ "y" => cr["row"]
101
+ }
102
+ end
103
+ ##
104
+ # Retrieve Sobel value for a given pixel.
105
+ def getSobel(x, y)
106
+ if !defined?(@sobels)
107
+ @grey ||= @original.grayscale
108
+ @sobel_x ||= [[-1,0,1], [-2,0,2], [-1,0,1]]
109
+ @sobel_y ||= [[-1,-2,-1], [ 0, 0, 0], [ 1, 2, 1]]
110
+ if x != 0 and x != (@width-1) and y != 0 and y != (@height-1)
111
+ t1=ChunkyPNG::Color.r(@grey[x-1,y-1])
112
+ t2=ChunkyPNG::Color.r(@grey[x,y-1])
113
+ t3=ChunkyPNG::Color.r(@grey[x+1,y-1])
114
+ t4=ChunkyPNG::Color.r(@grey[x-1,y])
115
+ t5=ChunkyPNG::Color.r(@grey[x,y])
116
+ t6=ChunkyPNG::Color.r(@grey[x+1,y])
117
+ t7=ChunkyPNG::Color.r(@grey[x-1,y+1])
118
+ t8=ChunkyPNG::Color.r(@grey[x,y+1])
119
+ t9=ChunkyPNG::Color.r(@grey[x+1,y+1])
120
+ pixel_x=(@sobel_x[0][0]*t1)+(@sobel_x[0][1]*t2)+(@sobel_x[0][2]*t3)+(@sobel_x[1][0]*t4)+(@sobel_x[1][1]*t5)+(@sobel_x[1][2]*t6)+(@sobel_x[2][0]*t7)+(@sobel_x[2][1]*t8)+(@sobel_x[2][2]*t9)
121
+ pixel_y=(@sobel_y[0][0]*t1)+(@sobel_y[0][1]*t2)+(@sobel_y[0][2]*t3)+(@sobel_y[1][0]*t4)+(@sobel_y[1][1]*t5)+(@sobel_y[1][2]*t6)+(@sobel_y[2][0]*t7)+(@sobel_y[2][1]*t8)+(@sobel_y[2][2]*t9)
122
+ return Math.sqrt(pixel_x * pixel_x + pixel_y * pixel_y).ceil
123
+ else
124
+ return 0
125
+ end
126
+ else
127
+ return @sobels[y * @width + x]
128
+ end
129
+ end
130
+ ##
131
+ # Retrieve the Sobel values for every pixel and set it as @sobel.
132
+ def getSobels
133
+ if !defined?(@sobels)
134
+ l = []
135
+ for xy in 0...(@width * @height)
136
+ s = self.getSobel(xy % @width, (xy/@width).floor)
137
+ l.push(s)
138
+ end
139
+ @sobels = l
140
+ end
141
+ return @sobels
142
+ end
143
+ ##
144
+ # Retrieve the Sobel value and color of a pixel.
145
+ def getSobelAndColor(x, y)
146
+ return {
147
+ "sobel" => self.getSobel(x, y),
148
+ "color" => self[x, y]
149
+ }
150
+ end
151
+ ##
152
+ # Retrieve the color of a pixel.
153
+ def [](x, y)
154
+ return @modified[x, y]
155
+ end
156
+ ##
157
+ # Set the color of a pixel.
158
+ def []=(x, y, color)
159
+ @modified[x, y] = color
160
+ end
161
+ ##
162
+ # Return the original, unmodified image.
163
+ def returnOriginal
164
+ return @original
165
+ end
166
+ ##
167
+ # Return the modified image.
168
+ def returnModified
169
+ return @modified
170
+ end
171
+ end
172
+ end
data/lib/pxlsrt/lines.rb CHANGED
@@ -87,8 +87,8 @@ module Pxlsrt
87
87
  # Outputs random slices of an array.
88
88
  # Because of the requirements of pxlsrt, it doesn't actually slice the array, but returns a range-like array. Example:
89
89
  # [[0, 5], [6, 7], [8, 10]]
90
- def self.randomSlices(arr, minLength, maxLength)
91
- len=arr.length-1
90
+ def self.randomSlices(mainLength, minLength, maxLength)
91
+ len=mainLength-1
92
92
  if len!=0
93
93
  min=[minLength, maxLength].min
94
94
  max=[maxLength, minLength].max
data/lib/pxlsrt/smart.rb CHANGED
@@ -28,7 +28,6 @@ module Pxlsrt
28
28
  :verbose => false,
29
29
  :absolute => false,
30
30
  :threshold => 20,
31
- :sorted => 2,
32
31
  :trusted => false,
33
32
  :middle => false
34
33
  }
@@ -41,7 +40,6 @@ module Pxlsrt
41
40
  :verbose => [false, true],
42
41
  :absolute => [false, true],
43
42
  :threshold => [{:class => [Float, Fixnum]}],
44
- :sorted => [{:class => [Fixnum]}],
45
43
  :trusted => [false, true],
46
44
  :middle => :anything
47
45
  }
@@ -66,166 +64,72 @@ module Pxlsrt
66
64
  return
67
65
  end
68
66
  Pxlsrt::Helpers.verbose("Smart mode.") if options[:verbose]
69
- case options[:reverse].downcase
70
- when "reverse"
71
- nre=1
72
- when "either"
73
- nre=-1
74
- else
75
- nre=0
76
- end
77
- img=input
78
- w,h=img.width,img.height
79
- sobel_x = [[-1,0,1], [-2,0,2], [-1,0,1]]
80
- sobel_y = [[-1,-2,-1], [ 0, 0, 0], [ 1, 2, 1]]
81
- edge = ChunkyPNG::Image.new(w, h, ChunkyPNG::Color::TRANSPARENT)
82
- valued="start"
83
- k=[]
84
- Pxlsrt::Helpers.verbose("Getting Sobel values and colors for pixels...") if options[:verbose]
85
- grey=img.grayscale
86
- for xy in 0..(w*h-1)
87
- x=xy % w
88
- y=(xy/w).floor
89
- if x!=0 and x!=(w-1) and y!=0 and y!=(h-1)
90
- t1=ChunkyPNG::Color.r(grey[x-1,y-1])
91
- t2=ChunkyPNG::Color.r(grey[x,y-1])
92
- t3=ChunkyPNG::Color.r(grey[x+1,y-1])
93
- t4=ChunkyPNG::Color.r(grey[x-1,y])
94
- t5=ChunkyPNG::Color.r(grey[x,y])
95
- t6=ChunkyPNG::Color.r(grey[x+1,y])
96
- t7=ChunkyPNG::Color.r(grey[x-1,y+1])
97
- t8=ChunkyPNG::Color.r(grey[x,y+1])
98
- t9=ChunkyPNG::Color.r(grey[x+1,y+1])
99
- pixel_x=(sobel_x[0][0]*t1)+(sobel_x[0][1]*t2)+(sobel_x[0][2]*t3)+(sobel_x[1][0]*t4)+(sobel_x[1][1]*t5)+(sobel_x[1][2]*t6)+(sobel_x[2][0]*t7)+(sobel_x[2][1]*t8)+(sobel_x[2][2]*t9)
100
- pixel_y=(sobel_y[0][0]*t1)+(sobel_y[0][1]*t2)+(sobel_y[0][2]*t3)+(sobel_y[1][0]*t4)+(sobel_y[1][1]*t5)+(sobel_y[1][2]*t6)+(sobel_y[2][0]*t7)+(sobel_y[2][1]*t8)+(sobel_y[2][2]*t9)
101
- val = Math.sqrt(pixel_x * pixel_x + pixel_y * pixel_y).ceil
102
- else
103
- val = 2000000000
104
- end
105
- k.push({ "sobel" => val, "pixel" => [x, y], "color" => Pxlsrt::Colors.getRGBA(img[x, y]) })
106
- end
107
- if options[:vertical]==true
108
- Pxlsrt::Helpers.verbose("Rotating image for vertical mode...") if options[:verbose]
109
- k=Pxlsrt::Lines.rotateImage(k,w,h,3)
110
- w,h=h,w
67
+ png=Pxlsrt::Image.new(input)
68
+ if !options[:vertical] and !options[:diagonal]
69
+ Pxlsrt::Helpers.verbose("Retrieving rows") if options[:verbose]
70
+ lines = png.horizontalLines
71
+ elsif options[:vertical] and !options[:diagonal]
72
+ Pxlsrt::Helpers.verbose("Retrieving columns") if options[:verbose]
73
+ lines = png.verticalLines
74
+ elsif !options[:vertical] and options[:diagonal]
75
+ Pxlsrt::Helpers.verbose("Retrieving diagonals") if options[:verbose]
76
+ lines = png.diagonalLines
77
+ elsif options[:vertical] and options[:diagonal]
78
+ Pxlsrt::Helpers.verbose("Retrieving diagonals") if options[:verbose]
79
+ lines = png.rDiagonalLines
111
80
  end
81
+ Pxlsrt::Helpers.verbose("Retrieving edges") if options[:verbose]
82
+ png.getSobels
112
83
  if !options[:diagonal]
113
- lines=Pxlsrt::Lines.imageRGBLines(k, w)
114
- Pxlsrt::Helpers.verbose("Determining bands with a#{options[:absolute] ? "n absolute" : " relative"} threshold of #{options[:threshold]}...") if options[:verbose]
115
- bands=Array.new()
116
- for j in lines
117
- slicing=true
118
- pixel=0
119
- m=Array.new()
120
- while slicing do
121
- n=Array.new
122
- if m.length > 1
123
- while m.last.length < options[:edge]
124
- if m.length > 1
125
- m[-2].concat(m[-1])
126
- m.pop
127
- else
128
- break
129
- end
130
- end
131
- end
132
- bandWorking=true
133
- while bandWorking do
134
- n.push(j[pixel]["color"])
135
- if (options[:absolute] ? (j[pixel+1]["sobel"]) : (j[pixel+1]["sobel"]-j[pixel]["sobel"])) > options[:threshold]
136
- bandWorking=false
137
- end
138
- if (pixel+1)==(j.length-1)
139
- n.push(j[pixel+1]["color"])
140
- slicing=false
141
- bandWorking=false
142
- end
143
- pixel+=1
144
- end
145
- m.push(n)
146
- end
147
- bands.concat(m)
148
- end
149
- Pxlsrt::Helpers.verbose("Pixel sorting using method '#{options[:method]}'...") if options[:verbose]
150
- image=[]
151
- if options[:smooth]
152
- for band in bands
153
- u=band.group_by {|x| x}
154
- image.concat(Pxlsrt::Lines.handleMiddlate(Pxlsrt::Colors.pixelSort(u.keys, options[:method], nre).map { |x| u[x] }.flatten(1), options[:middle]))
155
- end
156
- else
157
- for band in bands
158
- image.concat(Pxlsrt::Lines.handleMiddlate(Pxlsrt::Colors.pixelSort(band, options[:method], nre), options[:middle]))
159
- end
160
- end
84
+ iterator = 0...(lines.length)
161
85
  else
162
- Pxlsrt::Helpers.verbose("Determining diagonals...") if options[:verbose]
163
- dia=Pxlsrt::Lines.getDiagonals(k,w,h)
164
- Pxlsrt::Helpers.verbose("Determining bands with a#{options[:absolute] ? "n absolute" : " relative"} threshold of #{options[:threshold]}...") if options[:verbose]
165
- for j in dia.keys
166
- bands=[]
167
- if dia[j].length>1
168
- slicing=true
169
- pixel=0
170
- m=Array.new()
171
- while slicing do
172
- n=Array.new
173
- if m.length > 1
174
- while m.last.length < options[:edge]
175
- if m.length > 1
176
- m[-2].concat(m[-1])
177
- m.pop
178
- else
179
- break
180
- end
181
- end
182
- end
183
- bandWorking=true
184
- while bandWorking do
185
- n.push(dia[j][pixel]["color"])
186
- if (options[:absolute] ? (dia[j][pixel+1]["sobel"]) : (dia[j][pixel+1]["sobel"]-dia[j][pixel]["sobel"])) > options[:threshold]
187
- bandWorking=false
188
- end
189
- if (pixel+1)==(dia[j].length-1)
190
- n.push(dia[j][pixel+1]["color"])
191
- slicing=false
192
- bandWorking=false
193
- end
194
- pixel+=1
195
- end
196
- m.push(n)
86
+ iterator = lines.keys
87
+ end
88
+ Pxlsrt::Helpers.verbose("Dividing and pixel sorting lines") if options[:verbose]
89
+ for k in iterator
90
+ line = lines[k]
91
+ divisions = []
92
+ division = []
93
+ if line.length > 1
94
+ for pixel in 0...(line.length)
95
+ if !options[:vertical] and !options[:diagonal]
96
+ xy = png.horizontalXY(k, pixel)
97
+ elsif options[:vertical] and !options[:diagonal]
98
+ xy = png.verticalXY(k, pixel)
99
+ elsif !options[:vertical] and options[:diagonal]
100
+ xy = png.diagonalXY(k, pixel)
101
+ elsif options[:vertical] and options[:diagonal]
102
+ xy = png.rDiagonalXY(k, pixel)
197
103
  end
198
- else
199
- m=[[dia[j].first["color"]]]
200
- end
201
- dia[j]=bands.concat(m)
202
- end
203
- Pxlsrt::Helpers.verbose("Pixel sorting using method '#{options[:method]}'...") if options[:verbose]
204
- for j in dia.keys
205
- ell=[]
206
- if options[:smooth]
207
- for band in dia[j]
208
- u=band.group_by {|x| x}
209
- ell.concat(Pxlsrt::Lines.handleMiddlate(Pxlsrt::Colors.pixelSort(u.keys, options[:method], nre).map { |x| u[x] }.flatten(1), options[:middle]))
104
+ pxlSobel = png.getSobelAndColor(xy["x"], xy["y"])
105
+ if division.length == 0 or (options[:absolute] ? pxlSobel["sobel"] : pxlSobel["sobel"] - division.last["sobel"]) <= options[:threshold]
106
+ division.push(pxlSobel)
107
+ else
108
+ divisions.push(division)
109
+ division = [pxlSobel]
210
110
  end
211
- else
212
- for band in dia[j]
213
- ell.concat(Pxlsrt::Lines.handleMiddlate(Pxlsrt::Colors.pixelSort(band, options[:method], nre), options[:middle]))
111
+ if pixel == line.length - 1
112
+ divisions.push(division)
113
+ division = []
214
114
  end
215
115
  end
216
- dia[j]=ell
217
116
  end
218
- Pxlsrt::Helpers.verbose("Setting diagonals back to standard lines...") if options[:verbose]
219
- image=Pxlsrt::Lines.fromDiagonals(dia,w)
220
- end
221
- if options[:vertical]==true
222
- Pxlsrt::Helpers.verbose("Rotating back (because of vertical mode).") if options[:verbose]
223
- image=Pxlsrt::Lines.rotateImage(image,w,h,1)
224
- w,h=h,w
225
- end
226
- Pxlsrt::Helpers.verbose("Giving pixels new RGB values...") if options[:verbose]
227
- for px in 0..(w*h-1)
228
- edge[px % w, (px/w).floor]=Pxlsrt::Colors.arrayToRGBA(image[px])
117
+ newLine = []
118
+ for band in divisions
119
+ newLine.concat(
120
+ Pxlsrt::Helpers.handlePixelSort(
121
+ band.map { |sobelAndColor| sobelAndColor["color"] },
122
+ options
123
+ )
124
+ )
125
+ end
126
+ if !options[:diagonal]
127
+ png.replaceHorizontal(k, newLine) if !options[:vertical]
128
+ png.replaceVertical(k, newLine) if options[:vertical]
129
+ else
130
+ png.replaceDiagonal(k, newLine) if !options[:vertical]
131
+ png.replaceRDiagonal(k, newLine) if options[:vertical]
132
+ end
229
133
  end
230
134
  endTime=Time.now
231
135
  timeElapsed=endTime-startTime
@@ -237,7 +141,7 @@ module Pxlsrt
237
141
  Pxlsrt::Helpers.verbose("Took #{minutes} minute#{ minutes!=1 ? "s" : "" } and #{seconds} second#{ seconds!=1.0 ? "s" : "" }.") if options[:verbose]
238
142
  end
239
143
  Pxlsrt::Helpers.verbose("Returning ChunkyPNG::Image...") if options[:verbose]
240
- return edge
144
+ return png.returnModified
241
145
  else
242
146
  Pxlsrt::Helpers.error("Options specified do not follow the correct format.") if options[:verbose]
243
147
  return
@@ -1,5 +1,5 @@
1
1
  ##
2
2
  # The main module, your best friend.
3
3
  module Pxlsrt
4
- VERSION = "1.5.1"
4
+ VERSION = "1.6"
5
5
  end
data/lib/pxlsrt.rb CHANGED
@@ -1,6 +1,7 @@
1
- require "pxlsrt/version"
2
- require "pxlsrt/helpers"
3
- require "pxlsrt/lines"
4
- require "pxlsrt/colors"
5
- require "pxlsrt/brute"
1
+ require "pxlsrt/version"
2
+ require "pxlsrt/helpers"
3
+ require "pxlsrt/lines"
4
+ require "pxlsrt/image"
5
+ require "pxlsrt/colors"
6
+ require "pxlsrt/brute"
6
7
  require "pxlsrt/smart"
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.5.1
4
+ version: '1.6'
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-08-06 00:00:00.000000000 Z
11
+ date: 2014-08-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -79,6 +79,7 @@ files:
79
79
  - lib/pxlsrt/brute.rb
80
80
  - lib/pxlsrt/colors.rb
81
81
  - lib/pxlsrt/helpers.rb
82
+ - lib/pxlsrt/image.rb
82
83
  - lib/pxlsrt/lines.rb
83
84
  - lib/pxlsrt/smart.rb
84
85
  - lib/pxlsrt/version.rb