pixelart 1.2.3 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+
@@ -0,0 +1,116 @@
1
+ module Pixelart
2
+ class Image
3
+
4
+
5
+ def self.calc_stripes( length, n: 2, debug: false )
6
+ stripes = []
7
+
8
+ base_step = length / n ## pixels per pixel
9
+
10
+ err_step = (length % n) * 2 ## multiply by 2
11
+ denominator = n * 2 # denominator (in de - nenner e.g. 1/nenner 4/nenner)
12
+
13
+ overflow = err_step*n/denominator ## todo/check - assert that div is always WITHOUT remainder!!!!!
14
+
15
+ if debug
16
+ puts
17
+ puts "base_step (pixels per stripe):"
18
+ puts " #{base_step} - #{base_step}px * #{n} = #{base_step*n}px"
19
+ puts "err_step (in 1/#{length}*2):"
20
+ puts " #{err_step} / #{denominator} - #{err_step*n} / #{denominator} = +#{err_step*n/denominator}px overflow"
21
+ puts
22
+ end
23
+
24
+ err = 0
25
+ stripe = 0
26
+
27
+ n.times do |i|
28
+ stripe = base_step
29
+ err += err_step
30
+
31
+ if err >= denominator ## overflow
32
+ puts " -- overflow #{err}/#{denominator} - add +1 pixel to stripe #{i}" if debug
33
+
34
+ stripe += 1
35
+ err -= denominator
36
+ end
37
+
38
+
39
+ puts " #{i} => #{stripe} -- #{err} / #{denominator}" if debug
40
+
41
+ stripes[i] = stripe
42
+ end
43
+
44
+ ## note: assert calculation - sum of stripes MUST be equal length
45
+ sum = stripes.sum
46
+ puts " sum: #{sum}" if debug
47
+
48
+ if sum != length
49
+ puts "!! ERROR - stripes sum #{sum} calculation failed; expected #{length}:"
50
+ pp stripes
51
+ exit 1
52
+ end
53
+
54
+ stripes
55
+ end
56
+
57
+
58
+ def stripes_horizontal( *colors )
59
+ colors = colors.map { |color| Color.parse( color ) }
60
+
61
+ img = Image.new( @img.width, @img.height )
62
+
63
+ n = colors.size
64
+ lengths = self.class.calc_stripes( @img.height, n: n )
65
+
66
+ i = 0
67
+ length = lengths[0]
68
+ color = colors[0]
69
+
70
+ @img.height.times do |y|
71
+ if y >= length
72
+ i += 1
73
+ length += lengths[i]
74
+ color = colors[i]
75
+ end
76
+ @img.width.times do |x|
77
+ img[x,y] = color
78
+ end
79
+ end
80
+
81
+ img.compose!( self ) ## paste/compose image onto backgorund
82
+ img
83
+ end
84
+ alias_method :stripes, :stripes_horizontal
85
+
86
+
87
+
88
+ ### todo/check: move colors to (reusable) constants int Color !!!! why? why not?
89
+ RAINBOW_RED = Color.parse( '#E40303' )
90
+ RAINBOW_ORANGE = Color.parse( '#FF8C00' )
91
+ RAINBOW_YELLOW = Color.parse( '#FFED00' )
92
+ RAINBOW_GREEN = Color.parse( '#008026' )
93
+ RAINBOW_BLUE = Color.parse( '#004DFF' )
94
+ RAINBOW_VIOLET = Color.parse( '#750787' )
95
+
96
+
97
+ def rainbow
98
+ ##
99
+ # the most common variant consists of six stripes:
100
+ # red, orange, yellow, green, blue, and violet.
101
+ # The flag is typically flown horizontally,
102
+ # with the red stripe on top, as it would be in a natural rainbow
103
+ #
104
+ # see https://en.wikipedia.org/wiki/Rainbow_flag_(LGBT)
105
+ stripes( RAINBOW_RED,
106
+ RAINBOW_ORANGE,
107
+ RAINBOW_YELLOW,
108
+ RAINBOW_GREEN,
109
+ RAINBOW_BLUE,
110
+ RAINBOW_VIOLET )
111
+ end
112
+ alias_method :pride, :rainbow
113
+
114
+
115
+ end # class Image
116
+ end # module Pixelart
@@ -1,60 +1,60 @@
1
-
2
- module Pixelart
3
- class Image
4
-
5
- def transparent( style = :solid, fuzzy: false )
6
- img = Image.new( width, height )
7
-
8
-
9
- background = self[0,0]
10
-
11
- bh,bs,bl = Color.to_hsl( background )
12
- bh = (bh % 360) ## might might negative degree (always make positive)
13
-
14
- height.times do |y|
15
- if style == :linear
16
- background = self[0,y]
17
-
18
- bh,bs,bl = Color.to_hsl( background )
19
- bh = (bh % 360) ## might might negative degree (always make positive)
20
- end
21
- width.times do |x|
22
- pixel = self[x,y]
23
-
24
- if background == 0 ## special case if background is already transparent keep going
25
- img[x,y] = pixel
26
- elsif fuzzy
27
- ## check for more transparents
28
- ## not s is 0.0 to 0.99 (100%)
29
- ## and l is 0.0 to 0.99 (100%)
30
- h,s,l = Color.to_hsl( pixel )
31
- h = (h % 360) ## might might negative degree (always make positive)
32
-
33
- ## try some kind-of fuzzy "heuristic" match on background color
34
- if ((h >= bh-5) && (h <= bh+5)) &&
35
- ((s >= bs-0.07) && (s <= bs+0.07)) &&
36
- ((l >= bl-0.07) && (l <= bl+0.07))
37
- img[x,y] = 0 ## Color::TRANSPARENT
38
-
39
- if h != bh || s != bs || l != bl
40
- # report fuzzy background color
41
- puts " #{x}/#{y} fuzzy background #{[h,s,l]} ~= #{[bh,bs,bl]}"
42
- end
43
- else
44
- img[x,y] = pixel
45
- end
46
- else
47
- if pixel == background
48
- img[x,y] = 0 ## Color::TRANSPARENT
49
- else
50
- img[x,y] = pixel
51
- end
52
- end
53
- end
54
- end
55
- img
56
- end # method transparent
57
-
58
-
59
- end # class Image
60
- end # module Pixelart
1
+
2
+ module Pixelart
3
+ class Image
4
+
5
+ def transparent( style = :solid, fuzzy: false )
6
+ img = Image.new( width, height )
7
+
8
+
9
+ background = self[0,0]
10
+
11
+ bh,bs,bl = Color.to_hsl( background )
12
+ bh = (bh % 360) ## might might negative degree (always make positive)
13
+
14
+ height.times do |y|
15
+ if style == :linear
16
+ background = self[0,y]
17
+
18
+ bh,bs,bl = Color.to_hsl( background )
19
+ bh = (bh % 360) ## might might negative degree (always make positive)
20
+ end
21
+ width.times do |x|
22
+ pixel = self[x,y]
23
+
24
+ if background == 0 ## special case if background is already transparent keep going
25
+ img[x,y] = pixel
26
+ elsif fuzzy
27
+ ## check for more transparents
28
+ ## not s is 0.0 to 0.99 (100%)
29
+ ## and l is 0.0 to 0.99 (100%)
30
+ h,s,l = Color.to_hsl( pixel )
31
+ h = (h % 360) ## might might negative degree (always make positive)
32
+
33
+ ## try some kind-of fuzzy "heuristic" match on background color
34
+ if ((h >= bh-5) && (h <= bh+5)) &&
35
+ ((s >= bs-0.07) && (s <= bs+0.07)) &&
36
+ ((l >= bl-0.07) && (l <= bl+0.07))
37
+ img[x,y] = 0 ## Color::TRANSPARENT
38
+
39
+ if h != bh || s != bs || l != bl
40
+ # report fuzzy background color
41
+ puts " #{x}/#{y} fuzzy background #{[h,s,l]} ~= #{[bh,bs,bl]}"
42
+ end
43
+ else
44
+ img[x,y] = pixel
45
+ end
46
+ else
47
+ if pixel == background
48
+ img[x,y] = 0 ## Color::TRANSPARENT
49
+ else
50
+ img[x,y] = pixel
51
+ end
52
+ end
53
+ end
54
+ end
55
+ img
56
+ end # method transparent
57
+
58
+
59
+ end # class Image
60
+ end # module Pixelart