pixelart 1.2.2 → 1.3.1

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.
@@ -0,0 +1,120 @@
1
+ module Pixelart
2
+
3
+ class Image
4
+
5
+ def self.calc_sample_steps( width, new_width,
6
+ center: true,
7
+ debug: false )
8
+ ## todo/fix: assert new_width is smaller than width
9
+ if debug
10
+ puts
11
+ puts "==> from: #{width}px to: #{new_width}px"
12
+ end
13
+
14
+ indexes = []
15
+
16
+ base_step = width / new_width ## pixels per pixel
17
+
18
+ err_step = (width % new_width) * 2 ## multiply by 2
19
+ denominator = new_width * 2 # denominator (in de - nenner e.g. 1/nenner 4/nenner)
20
+
21
+ overflow = err_step*new_width/denominator ## todo/check - assert that div is always WITHOUT remainder!!!!!
22
+
23
+ if debug
24
+ puts
25
+ puts "base_step (pixels per pixel):"
26
+ puts " #{base_step} - #{base_step} * #{new_width}px = #{base_step*new_width}px"
27
+ puts "err_step (in 1/#{width}*2):"
28
+ puts " #{err_step} / #{denominator} - #{err_step*new_width} / #{denominator} = +#{err_step*new_width/denominator}px overflow"
29
+ puts
30
+ end
31
+
32
+ # initial pixel offset
33
+ index = 0
34
+ err = err_step/2 ## note: start off with +err_step/2 to add overflow pixel in the "middle"
35
+
36
+
37
+ index += if center.is_a?( Integer )
38
+ center
39
+ elsif center
40
+ base_step/2
41
+ else
42
+ 0 # use 0px offset
43
+ end
44
+
45
+
46
+ new_width.times do |i|
47
+ if err >= denominator ## overflow
48
+ puts " -- overflow #{err}/#{denominator} - add +1 pixel offset to #{i}" if debug
49
+ index += 1
50
+ err -= denominator
51
+ end
52
+
53
+ puts " #{i} => #{index} -- #{err} / #{denominator}" if debug
54
+
55
+
56
+ indexes[i] = index
57
+
58
+ index += base_step
59
+ err += err_step
60
+ end
61
+
62
+ indexes
63
+ end
64
+
65
+
66
+
67
+ ## todo/check: rename to sample to resample or downsample - why? why not?
68
+ def sample( steps_x, steps_y=steps_x,
69
+ top_x: 0, top_y: 0 )
70
+ width = steps_x.size
71
+ height = steps_y.size
72
+ puts " downsampling from #{self.width}x#{self.height} to #{width}x#{height}..."
73
+
74
+ dest = Image.new( width, height )
75
+
76
+ steps_x.each_with_index do |step_x, x|
77
+ steps_y.each_with_index do |step_y, y|
78
+ pixel = self[top_x+step_x, top_y+step_y]
79
+
80
+ dest[x,y] = pixel
81
+ end
82
+ end
83
+
84
+ dest
85
+ end
86
+ alias_method :pixelate, :sample
87
+
88
+
89
+ def sample_debug( steps_x, steps_y=steps_x,
90
+ color: Color.parse( '#ffff00' ),
91
+ top_x: 0,
92
+ top_y: 0) ## add a yellow pixel
93
+
94
+ ## todo/fix: get a clone of the image (DO NOT modify in place)
95
+
96
+ img = self
97
+
98
+ steps_x.each_with_index do |step_x, x|
99
+ steps_y.each_with_index do |step_y, y|
100
+ base_x = top_x+step_x
101
+ base_y = top_y+step_y
102
+
103
+ img[base_x,base_y] = color
104
+
105
+ ## add more colors
106
+ img[base_x+1,base_y] = color
107
+ img[base_x+2,base_y] = color
108
+
109
+ img[base_x,base_y+1] = color
110
+ img[base_x,base_y+2] = color
111
+ end
112
+ end
113
+
114
+ self
115
+ end
116
+ alias_method :pixelate_debug, :sample_debug
117
+
118
+ end # class Image
119
+ end # module Pixelart
120
+
@@ -1,35 +1,35 @@
1
- module Pixelart
2
-
3
-
4
- ## todo/check:
5
- ## use a different name for silhouette
6
- ## - why not - outline ???
7
- ## or - shadow ???
8
- ## or - profile ???
9
- ## or - figure ???
10
- ## or - shape ???
11
- ## or - form ???
12
-
13
- class Image
14
- def silhouette( color='#000000' )
15
- color = Color.parse( color )
16
-
17
- img = Image.new( @img.width, @img.height )
18
-
19
- @img.width.times do |x|
20
- @img.height.times do |y|
21
- pixel = @img[x,y]
22
-
23
- img[x,y] = if pixel == Color::TRANSPARENT # transparent (0)
24
- Color::TRANSPARENT
25
- else
26
- color
27
- end
28
- end
29
- end
30
- img
31
- end
32
-
33
- end # class Image
34
-
35
- end # module Pixelart
1
+ module Pixelart
2
+
3
+
4
+ ## todo/check:
5
+ ## use a different name for silhouette
6
+ ## - why not - outline ???
7
+ ## or - shadow ???
8
+ ## or - profile ???
9
+ ## or - figure ???
10
+ ## or - shape ???
11
+ ## or - form ???
12
+
13
+ class Image
14
+ def silhouette( color='#000000' )
15
+ color = Color.parse( color )
16
+
17
+ img = Image.new( @img.width, @img.height )
18
+
19
+ @img.width.times do |x|
20
+ @img.height.times do |y|
21
+ pixel = @img[x,y]
22
+
23
+ img[x,y] = if pixel == Color::TRANSPARENT # transparent (0)
24
+ Color::TRANSPARENT
25
+ else
26
+ color
27
+ end
28
+ end
29
+ end
30
+ img
31
+ end
32
+
33
+ end # class Image
34
+
35
+ end # module Pixelart
@@ -1,69 +1,69 @@
1
- module Pixelart
2
-
3
-
4
-
5
- class Image
6
- def sketch( sketch=4, line: 1 )
7
- # todo: line - find a better name eg. line_strenght/width or such?
8
- width = @img.width*sketch + (@img.width+1)*line
9
- height = @img.height*sketch + (@img.height+1)*line
10
-
11
- puts " #{width}x#{height}"
12
-
13
- img = Image.new( width, height, Color::WHITE )
14
-
15
- @img.width.times do |x|
16
- @img.height.times do |y|
17
- pixel = @img[x,y]
18
-
19
- ## get surrounding pixels - if "out-of-bound" use transparent (0)
20
- left = x == 0 ? Color::TRANSPARENT : @img[x-1,y]
21
- top = y == 0 ? Color::TRANSPARENT : @img[x ,y-1]
22
-
23
- if pixel != left ## draw vertical line
24
- (sketch+line*2).times do |n|
25
- line.times do |m|
26
- img[ x*sketch + line*x + m,
27
- n + y*sketch + line*y] = Color::BLACK
28
- end
29
- end
30
- end
31
-
32
- if pixel != top ## draw horizontal line
33
- (sketch+line*2).times do |n|
34
- line.times do |m|
35
- img[n + x*sketch + line*x,
36
- y*sketch + line*y + m] = Color::BLACK
37
- end
38
- end
39
- end
40
-
41
-
42
- ## check special edge case for x and y to add "finish-up" right and bottom line
43
- if x == @img.width-1 && pixel != Color::TRANSPARENT
44
- ## draw vertical line
45
- (sketch+line*2).times do |n|
46
- line.times do |m|
47
- img[ (x+1)*sketch + line*(x+1) + m,
48
- n + y*sketch + line*y] = Color::BLACK
49
- end
50
- end
51
- end
52
-
53
- if y== @img.height-1 && pixel != Color::TRANSPARENT
54
- ## draw horizontal line
55
- (sketch+line*2).times do |n|
56
- line.times do |m|
57
- img[n + x*sketch + line*x,
58
- (y+1)*sketch + line*(y+1) + m] = Color::BLACK
59
- end
60
- end
61
- end
62
- end
63
- end
64
-
65
- img
66
- end
67
- end # class Image
68
- end # module Pixelart
69
-
1
+ module Pixelart
2
+
3
+
4
+
5
+ class Image
6
+ def sketch( sketch=4, line: 1 )
7
+ # todo: line - find a better name eg. line_strenght/width or such?
8
+ width = @img.width*sketch + (@img.width+1)*line
9
+ height = @img.height*sketch + (@img.height+1)*line
10
+
11
+ puts " #{width}x#{height}"
12
+
13
+ img = Image.new( width, height, Color::WHITE )
14
+
15
+ @img.width.times do |x|
16
+ @img.height.times do |y|
17
+ pixel = @img[x,y]
18
+
19
+ ## get surrounding pixels - if "out-of-bound" use transparent (0)
20
+ left = x == 0 ? Color::TRANSPARENT : @img[x-1,y]
21
+ top = y == 0 ? Color::TRANSPARENT : @img[x ,y-1]
22
+
23
+ if pixel != left ## draw vertical line
24
+ (sketch+line*2).times do |n|
25
+ line.times do |m|
26
+ img[ x*sketch + line*x + m,
27
+ n + y*sketch + line*y] = Color::BLACK
28
+ end
29
+ end
30
+ end
31
+
32
+ if pixel != top ## draw horizontal line
33
+ (sketch+line*2).times do |n|
34
+ line.times do |m|
35
+ img[n + x*sketch + line*x,
36
+ y*sketch + line*y + m] = Color::BLACK
37
+ end
38
+ end
39
+ end
40
+
41
+
42
+ ## check special edge case for x and y to add "finish-up" right and bottom line
43
+ if x == @img.width-1 && pixel != Color::TRANSPARENT
44
+ ## draw vertical line
45
+ (sketch+line*2).times do |n|
46
+ line.times do |m|
47
+ img[ (x+1)*sketch + line*(x+1) + m,
48
+ n + y*sketch + line*y] = Color::BLACK
49
+ end
50
+ end
51
+ end
52
+
53
+ if y== @img.height-1 && pixel != Color::TRANSPARENT
54
+ ## draw horizontal line
55
+ (sketch+line*2).times do |n|
56
+ line.times do |m|
57
+ img[n + x*sketch + line*x,
58
+ (y+1)*sketch + line*(y+1) + m] = Color::BLACK
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ img
66
+ end
67
+ end # class Image
68
+ end # module Pixelart
69
+
@@ -1,146 +1,146 @@
1
- module Pixelart
2
-
3
- class Image
4
-
5
-
6
- def spots_hidef( spot=10,
7
- spacing: 0,
8
- center: nil,
9
- radius: nil,
10
- background: nil,
11
- lightness: nil,
12
- odd: false )
13
-
14
- width = @img.width*spot+(@img.width-1)*spacing
15
- height = @img.height*spot+(@img.height-1)*spacing
16
-
17
- ## puts " #{width}x#{height}"
18
-
19
- ## settings in a hash for "pretty printing" in comments
20
- settings = { spot: spot
21
- }
22
-
23
- settings[ :spacing ] = spacing if spacing
24
- settings[ :center ] = center if center
25
- settings[ :radius ] = radius if radius
26
- settings[ :background ] = background if background
27
- settings[ :lightness ] = lightness if lightness
28
- settings[ :odd ] = odd if odd
29
-
30
-
31
- v = Vector.new( width, height, header: <<TXT )
32
- generated by pixelart/v#{VERSION} on #{Time.now.utc}
33
-
34
- spots_hidef with settings:
35
- #{settings.to_json}
36
- TXT
37
-
38
-
39
- min_center, max_center = center ? center : [0,0]
40
- min_radius, max_radius = radius ? radius : [0,0]
41
-
42
- ## note: allow passing in array of colors (will get randomally picked)
43
- background_colors = if background
44
- ## check for array; otherwise assume single color passed in
45
- background_ary = background.is_a?( Array) ? background : [background]
46
- background_ary.map { |background| Color.parse( background ) }
47
- else
48
- [0] # transparent (default - no background)
49
- end
50
-
51
-
52
- min_lightness, max_lightness = lightness ? lightness : [0.0,0.0]
53
-
54
-
55
- @img.width.times do |x|
56
- @img.height.times do |y|
57
- color = @img[ x, y ]
58
-
59
- if color == 0 ## transparent
60
- next if background.nil?
61
-
62
- color = if background_colors.size == 1
63
- background_colors[0]
64
- else ## pick random background color
65
- background_colors[ rand( background_colors.size ) ]
66
- end
67
- end
68
-
69
-
70
- if lightness
71
- ## todo/check: make it work with alpha too
72
- h,s,l = Color.to_hsl( color, include_alpha: false )
73
-
74
- h = h % 360 ## make sure h(ue) is always positive!!!
75
-
76
- ## note: rand() return between 0.0 and 1.0
77
- l_diff = min_lightness +
78
- (max_lightness-min_lightness)*rand()
79
-
80
- lnew = [1.0, l+l_diff].min
81
- lnew = [0.0, lnew].max
82
-
83
- ## print " #{l}+#{l_diff}=#{lnew} "
84
-
85
- color = Color.from_hsl( h,
86
- [1.0, s].min,
87
- lnew )
88
- end
89
-
90
- ## note: return hexstring with leading #
91
- # e.g. 0 becomes #00000000
92
- # and so on
93
- color_hex = Color.to_hex( color, include_alpha: true )
94
-
95
- cx_offset,
96
- cy_offset = if center ## randomize (offset off center +/-)
97
- [(spot/2 + min_center) + rand( max_center-min_center ),
98
- (spot/2 + min_center) + rand( max_center-min_center )]
99
- else
100
- [spot/2, ## center
101
- spot/2]
102
- end
103
-
104
- cx = x*spot + x*spacing + cx_offset
105
- cy = y*spot + y*spacing + cx_offset
106
-
107
- r = if radius ## randomize (radius +/-)
108
- min_radius + rand( max_radius-min_radius )
109
- else
110
- spot/2
111
- end
112
-
113
- cx += spot/2 if odd && (y % 2 == 1) ## add odd offset
114
-
115
-
116
- v.circle( cx: cx, cy: cy, r: r, fill: color_hex)
117
- end
118
- end
119
- v
120
- end ## method spots_hidef
121
- alias_method :spots_hd, :spots_hidef
122
-
123
-
124
- def spots( spot=10,
125
- spacing: 0,
126
- center: nil,
127
- radius: nil,
128
- background: nil,
129
- lightness: nil,
130
- odd: false )
131
-
132
- v = spots_hidef( spot,
133
- spacing: spacing,
134
- center: center,
135
- radius: radius,
136
- background: background,
137
- lightness: lightness,
138
- odd: odd )
139
-
140
- v.to_image
141
- end
142
-
143
-
144
- end # class Image
145
- end # class Pixelart
146
-
1
+ module Pixelart
2
+
3
+ class Image
4
+
5
+
6
+ def spots_hidef( spot=10,
7
+ spacing: 0,
8
+ center: nil,
9
+ radius: nil,
10
+ background: nil,
11
+ lightness: nil,
12
+ odd: false )
13
+
14
+ width = @img.width*spot+(@img.width-1)*spacing
15
+ height = @img.height*spot+(@img.height-1)*spacing
16
+
17
+ ## puts " #{width}x#{height}"
18
+
19
+ ## settings in a hash for "pretty printing" in comments
20
+ settings = { spot: spot
21
+ }
22
+
23
+ settings[ :spacing ] = spacing if spacing
24
+ settings[ :center ] = center if center
25
+ settings[ :radius ] = radius if radius
26
+ settings[ :background ] = background if background
27
+ settings[ :lightness ] = lightness if lightness
28
+ settings[ :odd ] = odd if odd
29
+
30
+
31
+ v = Vector.new( width, height, header: <<TXT )
32
+ generated by pixelart/v#{VERSION} on #{Time.now.utc}
33
+
34
+ spots_hidef with settings:
35
+ #{settings.to_json}
36
+ TXT
37
+
38
+
39
+ min_center, max_center = center ? center : [0,0]
40
+ min_radius, max_radius = radius ? radius : [0,0]
41
+
42
+ ## note: allow passing in array of colors (will get randomally picked)
43
+ background_colors = if background
44
+ ## check for array; otherwise assume single color passed in
45
+ background_ary = background.is_a?( Array) ? background : [background]
46
+ background_ary.map { |background| Color.parse( background ) }
47
+ else
48
+ [0] # transparent (default - no background)
49
+ end
50
+
51
+
52
+ min_lightness, max_lightness = lightness ? lightness : [0.0,0.0]
53
+
54
+
55
+ @img.width.times do |x|
56
+ @img.height.times do |y|
57
+ color = @img[ x, y ]
58
+
59
+ if color == 0 ## transparent
60
+ next if background.nil?
61
+
62
+ color = if background_colors.size == 1
63
+ background_colors[0]
64
+ else ## pick random background color
65
+ background_colors[ rand( background_colors.size ) ]
66
+ end
67
+ end
68
+
69
+
70
+ if lightness
71
+ ## todo/check: make it work with alpha too
72
+ h,s,l = Color.to_hsl( color, include_alpha: false )
73
+
74
+ h = h % 360 ## make sure h(ue) is always positive!!!
75
+
76
+ ## note: rand() return between 0.0 and 1.0
77
+ l_diff = min_lightness +
78
+ (max_lightness-min_lightness)*rand()
79
+
80
+ lnew = [1.0, l+l_diff].min
81
+ lnew = [0.0, lnew].max
82
+
83
+ ## print " #{l}+#{l_diff}=#{lnew} "
84
+
85
+ color = Color.from_hsl( h,
86
+ [1.0, s].min,
87
+ lnew )
88
+ end
89
+
90
+ ## note: return hexstring with leading #
91
+ # e.g. 0 becomes #00000000
92
+ # and so on
93
+ color_hex = Color.to_hex( color, include_alpha: true )
94
+
95
+ cx_offset,
96
+ cy_offset = if center ## randomize (offset off center +/-)
97
+ [(spot/2 + min_center) + rand( max_center-min_center ),
98
+ (spot/2 + min_center) + rand( max_center-min_center )]
99
+ else
100
+ [spot/2, ## center
101
+ spot/2]
102
+ end
103
+
104
+ cx = x*spot + x*spacing + cx_offset
105
+ cy = y*spot + y*spacing + cx_offset
106
+
107
+ r = if radius ## randomize (radius +/-)
108
+ min_radius + rand( max_radius-min_radius )
109
+ else
110
+ spot/2
111
+ end
112
+
113
+ cx += spot/2 if odd && (y % 2 == 1) ## add odd offset
114
+
115
+
116
+ v.circle( cx: cx, cy: cy, r: r, fill: color_hex)
117
+ end
118
+ end
119
+ v
120
+ end ## method spots_hidef
121
+ alias_method :spots_hd, :spots_hidef
122
+
123
+
124
+ def spots( spot=10,
125
+ spacing: 0,
126
+ center: nil,
127
+ radius: nil,
128
+ background: nil,
129
+ lightness: nil,
130
+ odd: false )
131
+
132
+ v = spots_hidef( spot,
133
+ spacing: spacing,
134
+ center: center,
135
+ radius: radius,
136
+ background: background,
137
+ lightness: lightness,
138
+ odd: odd )
139
+
140
+ v.to_image
141
+ end
142
+
143
+
144
+ end # class Image
145
+ end # class Pixelart
146
+