pxlsrt 1.5.1 → 1.6

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: 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