pixelart 1.2.3 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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