pixelart 1.1.0 → 1.2.2

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
  SHA256:
3
- metadata.gz: bb520f7fc94b0b7d62336829d92929bbeb27600f0042ab3f68d81b6e5b26d2b3
4
- data.tar.gz: ed4756f69b5f5d5ca696a1105aa348b5b86ab33653ff7c34d1b24f4dc75e244f
3
+ metadata.gz: 6be97cd0f30e95965b6ca21d69142283d1e2869ba99e37b84245b5d95c47fda0
4
+ data.tar.gz: 2bc68cf7a70d718e2d96b92f4401f44074b01282cb5ede85d548b36edac7d3d6
5
5
  SHA512:
6
- metadata.gz: caa3d9eeb12a4a59e4f6ec3191e432ae11d7cf44465e0b6722c69bda985af6caeea3a4390f773d4d535a38096f483c3d9467b03f63ed6547a168f79361db1991
7
- data.tar.gz: d7f6d039eddc337b62ca22b338712a26423781b2a57703429469d376c02af0fef6aadd9182f4fb2cb755dc83f27c6bcbb97519ee528c01169ba8070534c7c377
6
+ metadata.gz: c329166bd2144e1e440d01447c9babc6d999de0aed2d9eb3dedaa521b016b829f0039d8fdf5475afeffbc46f2f75f1efaca1a95f73a3c3e968d653041ff4656a
7
+ data.tar.gz: 44ab750a9bdec98770ff6ed325b8fac5883e693ae3356b08012184bdf72a20c1c88a023fb883dc437311df043d6a2d23012f54309d70dfa8e3402deb5683e945
data/Manifest.txt CHANGED
@@ -13,6 +13,9 @@ lib/pixelart/led.rb
13
13
  lib/pixelart/misc.rb
14
14
  lib/pixelart/palette.rb
15
15
  lib/pixelart/pixelator.rb
16
+ lib/pixelart/silhouette.rb
16
17
  lib/pixelart/sketch.rb
17
18
  lib/pixelart/spots.rb
19
+ lib/pixelart/transparent.rb
20
+ lib/pixelart/vector.rb
18
21
  lib/pixelart/version.rb
data/README.md CHANGED
@@ -3,8 +3,8 @@
3
3
  pixelart - mint your own pixel art images off chain using any design (in ascii text) in any colors; incl. 2x/4x/8x zoom for bigger sizes
4
4
 
5
5
 
6
- * home :: [github.com/rubycoco/pixel](https://github.com/rubycoco/pixel)
7
- * bugs :: [github.com/rubycoco/pixel/issues](https://github.com/rubycoco/pixel/issues)
6
+ * home :: [github.com/pixelartexchange/pixel](https://github.com/pixelartexchange/pixel)
7
+ * bugs :: [github.com/pixelartexchange/pixel/issues](https://github.com/pixelartexchange/pixel/issues)
8
8
  * gem :: [rubygems.org/gems/pixelart](https://rubygems.org/gems/pixelart)
9
9
  * rdoc :: [rubydoc.info/gems/pixelart](http://rubydoc.info/gems/pixelart)
10
10
 
@@ -71,8 +71,8 @@ img3x.save( './i/mooncat_white-3x.png' )
71
71
 
72
72
  Voila!
73
73
 
74
- ![](https://github.com/rubycoco/pixel/raw/master/pixelart/i/mooncat_white.png)
75
- ![](https://github.com/rubycoco/pixel/raw/master/pixelart/i/mooncat_white-3x.png)
74
+ ![](https://github.com/pixelartexchange/pixel/raw/master/pixelart/i/mooncat_white.png)
75
+ ![](https://github.com/pixelartexchange/pixel/raw/master/pixelart/i/mooncat_white-3x.png)
76
76
 
77
77
 
78
78
 
@@ -100,8 +100,8 @@ img3x.save( './i/mooncat_black-3x.png' )
100
100
 
101
101
  Voila! Black is the new White!
102
102
 
103
- ![](https://github.com/rubycoco/pixel/raw/master/pixelart/i/mooncat_black.png)
104
- ![](https://github.com/rubycoco/pixel/raw/master/pixelart/i/mooncat_black-3x.png)
103
+ ![](https://github.com/pixelartexchange/pixel/raw/master/pixelart/i/mooncat_black.png)
104
+ ![](https://github.com/pixelartexchange/pixel/raw/master/pixelart/i/mooncat_black-3x.png)
105
105
 
106
106
 
107
107
 
@@ -227,8 +227,8 @@ img5x.save( './i/vader5x.png' )
227
227
 
228
228
  Voila!
229
229
 
230
- ![](https://github.com/rubycoco/pixel/raw/master/pixelart/i/vader.png)
231
- ![](https://github.com/rubycoco/pixel/raw/master/pixelart/i/vader5x.png)
230
+ ![](https://github.com/pixelartexchange/pixel/raw/master/pixelart/i/vader.png)
231
+ ![](https://github.com/pixelartexchange/pixel/raw/master/pixelart/i/vader5x.png)
232
232
 
233
233
 
234
234
 
@@ -288,4 +288,3 @@ Just install the gem:
288
288
 
289
289
  The scripts are dedicated to the public domain.
290
290
  Use it as you please with no restrictions whatsoever.
291
-
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ Hoe.spec 'pixelart' do
8
8
  self.summary = "pixelart - mint your own pixel art images off chain using any design (in ascii text) in any colors; incl. 2x/4x/8x zoom for bigger sizes"
9
9
  self.description = summary
10
10
 
11
- self.urls = { home: 'https://github.com/rubycoco/pixel' }
11
+ self.urls = { home: 'https://github.com/pixelartexchange/pixel' }
12
12
 
13
13
  self.author = 'Gerald Bauer'
14
14
  self.email = 'wwwmake@googlegroups.com'
@@ -20,6 +20,7 @@ Hoe.spec 'pixelart' do
20
20
  self.extra_deps = [
21
21
  ['chunky_png'],
22
22
  ['mini_magick'],
23
+ ['csvreader'],
23
24
  ]
24
25
 
25
26
  self.licenses = ['Public Domain']
data/lib/pixelart/base.rb CHANGED
@@ -7,6 +7,9 @@ require 'chunky_png'
7
7
  require 'mini_magick'
8
8
 
9
9
 
10
+ # bonus / prologue / convenience 3rd party
11
+ require 'csvreader'
12
+
10
13
 
11
14
  ## stdlib
12
15
  require 'pp'
@@ -28,14 +31,18 @@ require 'pixelart/palette'
28
31
  require 'pixelart/image'
29
32
  require 'pixelart/composite'
30
33
 
34
+
31
35
  require 'pixelart/pixelator'
32
36
 
33
37
  require 'pixelart/misc' ## misc helpers
34
38
 
35
39
  #########################
36
- # (special) effects / filters
40
+ # (special) effects / filters / etc
37
41
  require 'pixelart/led'
38
42
  require 'pixelart/sketch'
43
+ require 'pixelart/transparent'
44
+ require 'pixelart/silhouette'
45
+
39
46
 
40
47
  ## (special) effects / filters that require imagemagick
41
48
 
@@ -47,6 +54,9 @@ module Pixelart
47
54
  MAGICK_OUTPUT = './tmp/magick_output.png'
48
55
  end
49
56
 
57
+ require 'pixelart/vector' ## vector graphics helpers
58
+
59
+
50
60
  require 'pixelart/spots'
51
61
  require 'pixelart/blur'
52
62
 
@@ -7,10 +7,31 @@ class ImageComposite < Image # check: (re)name to Collage, Sheet, Sprites, or s
7
7
  TILE_HEIGHT = 24
8
8
 
9
9
 
10
+ def self.read( path, width: TILE_WIDTH, height: TILE_WIDTH ) ## convenience helper
11
+ img = ChunkyPNG::Image.from_file( path )
12
+ new( img, width: width,
13
+ height: width )
14
+ end
15
+
16
+
10
17
  def initialize( *args, **kwargs )
11
18
  @tile_width = kwargs[:width] || kwargs[:tile_width] || TILE_WIDTH
12
19
  @tile_height = kwargs[:height] || kwargs[:tile_height] || TILE_HEIGHT
13
20
 
21
+ ## check for background
22
+ background = kwargs[:background] || kwargs[:tile_background]
23
+
24
+ if background
25
+ ## wrap into an array if not already an array
26
+ ## and convert all colors to true rgba colors as integer numbers
27
+ background = [background] unless background.is_a?( Array )
28
+ @background_colors = background.map { |color| Color.parse( color ) }
29
+ else
30
+ ## todo/check: use empty array instead of nil - why? why not?
31
+ @background_colors = nil
32
+ end
33
+
34
+
14
35
  ## todo/fix: check type - args[0] is Image!!!
15
36
  if args.size == 1 ## assume "copy" c'tor with passed in image
16
37
  img = args[0] ## pass image through as-is
@@ -25,12 +46,25 @@ class ImageComposite < Image # check: (re)name to Collage, Sheet, Sprites, or s
25
46
  @tile_rows = args[1] || 3
26
47
  @tile_count = 0 # (track) current index (of added images)
27
48
 
28
- img = ChunkyPNG::Image.new( @tile_cols * @tile_width,
29
- @tile_rows * @tile_height )
49
+ background_color = if @background_colors && @background_colors.size == 1
50
+ @background_colors[0]
51
+ else
52
+ 0 # note: 0 is transparent (0) true color
53
+ end
54
+
55
+ ## todo/check - always auto-fill complete image (even if empty/no tiles)
56
+ ## with background color if only one background color
57
+ ## why? why not??? or always follow the "model"
58
+ ## with more than one background color???
59
+ img = ChunkyPNG::Image.new( @tile_cols * @tile_width,
60
+ @tile_rows * @tile_height,
61
+ background_color )
62
+
30
63
  else
31
64
  raise ArgumentError, "cols, rows or image arguments expected; got: #{args.inspect}"
32
65
  end
33
66
 
67
+
34
68
  puts " #{img.height}x#{img.width} (height x width)"
35
69
 
36
70
  super( nil, nil, img )
@@ -39,19 +73,46 @@ class ImageComposite < Image # check: (re)name to Collage, Sheet, Sprites, or s
39
73
 
40
74
  def count() @tile_count; end
41
75
  alias_method :size, :count ## add size alias (confusing if starting with 0?) - why? why not?
76
+ alias_method :tile_count, :count
77
+
78
+ def tile_width() @tile_width; end
79
+ def tile_height() @tile_height; end
80
+
81
+
42
82
 
43
83
  #####
44
84
  # set / add tile
45
-
46
- def add( image )
85
+ def _add( image )
47
86
  y, x = @tile_count.divmod( @tile_cols )
48
87
 
49
88
  puts " [#{@tile_count}] @ (#{x}/#{y}) #{image.width}x#{image.height} (height x width)"
50
89
 
90
+ ## note: only used if more than one background color specified
91
+ ## needs to cycle through
92
+ if @background_colors && @background_colors.size > 1
93
+ i = x + y*@tile_cols
94
+
95
+ ## note: cycle through background color for now
96
+ background_color = @background_colors[i % @background_colors.size]
97
+ background = Image.new( @tile_width, @tile_height, background_color ) ## todo/chekc: use "raw" ChunkyPNG:Image here - why? why not?
98
+ background.compose!( image )
99
+ image = background ## switch - make image with background new image
100
+ end
101
+
51
102
  ## note: image.image - "unwrap" the "raw" ChunkyPNG::Image
52
103
  @img.compose!( image.image, x*@tile_width, y*@tile_height )
53
104
  @tile_count += 1
54
105
  end
106
+
107
+ def add( image_or_images ) ## note: allow adding of image OR array of images
108
+ if image_or_images.is_a?( Array )
109
+ images = image_or_images
110
+ images.each { |image| _add( image ) }
111
+ else
112
+ image = image_or_images
113
+ _add( image )
114
+ end
115
+ end
55
116
  alias_method :<<, :add
56
117
 
57
118
 
@@ -73,5 +134,21 @@ class ImageComposite < Image # check: (re)name to Collage, Sheet, Sprites, or s
73
134
  super ## e.g [x,y] --- get pixel
74
135
  end
75
136
  end
137
+
138
+
139
+ ## convenience helpers to loop over composite
140
+ def each( &block )
141
+ count.times do |i|
142
+ block.call( tile( i ) )
143
+ end
144
+ end
145
+
146
+ def each_with_index( &block )
147
+ count.times do |i|
148
+ block.call( tile( i ), i )
149
+ end
150
+ end
151
+
152
+
76
153
  end # class ImageComposite
77
154
  end # module Pixelart
@@ -64,18 +64,21 @@ end
64
64
 
65
65
 
66
66
 
67
- def zoom( zoom=2 )
67
+ def zoom( zoom=2, spacing: 0 )
68
68
  ## create a new zoom factor x image (2x, 3x, etc.)
69
69
 
70
- img = Image.new( @img.width*zoom,
71
- @img.height*zoom )
70
+ width = @img.width*zoom+(@img.width-1)*spacing
71
+ height = @img.height*zoom+(@img.height-1)*spacing
72
72
 
73
- @img.height.times do |y|
74
- @img.width.times do |x|
73
+ img = Image.new( width, height )
74
+
75
+ @img.width.times do |x|
76
+ @img.height.times do |y|
75
77
  pixel = @img[x,y]
76
78
  zoom.times do |n|
77
79
  zoom.times do |m|
78
- img[n+zoom*x,m+zoom*y] = pixel
80
+ img[n+zoom*x+spacing*x,
81
+ m+zoom*y+spacing*y] = pixel
79
82
  end
80
83
  end
81
84
  end # each x
@@ -86,6 +89,12 @@ end
86
89
  alias_method :scale, :zoom
87
90
 
88
91
 
92
+ def crop( x, y, crop_width, crop_height )
93
+ Image.new( nil, nil,
94
+ image.crop( x,y, crop_width, crop_height ) )
95
+ end
96
+
97
+
89
98
 
90
99
  #######################
91
100
  ## filter / effects
@@ -94,12 +103,25 @@ def grayscale
94
103
  img = @img.grayscale
95
104
  Image.new( img.width, img.height, img )
96
105
  end
106
+ alias_method :greyscale, :grayscale
107
+
108
+
109
+
110
+ def flip
111
+ img = @img.flip
112
+ Image.new( img.width, img.height, img )
113
+ end
114
+ alias_method :flip_horizontally, :flip
97
115
 
98
116
  def mirror
99
117
  img = @img.mirror
100
118
  Image.new( img.width, img.height, img )
101
119
  end
102
120
  alias_method :flip_vertically, :mirror
121
+ alias_method :flop, :mirror
122
+
123
+
124
+
103
125
 
104
126
 
105
127
  ## add replace_colors alias too? - why? why not?
@@ -0,0 +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
@@ -3,41 +3,67 @@ module Pixelart
3
3
  class Image
4
4
 
5
5
 
6
- def spots( spot=10,
7
- spacing: 0,
8
- center: nil,
9
- radius: nil,
10
- background: nil,
11
- lightness: nil,
12
- odd: false )
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
13
16
 
14
- width = @img.width
15
- height = @img.height
16
17
  ## puts " #{width}x#{height}"
17
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
+
18
39
  min_center, max_center = center ? center : [0,0]
19
40
  min_radius, max_radius = radius ? radius : [0,0]
20
41
 
21
- background_color = background ? Color.parse( background ) : 0
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
22
50
 
23
- min_lightness, max_lightness = lightness ? lightness : [0.0,0.0]
24
51
 
25
- ## note: magick command line might get way too long, thus,
26
- ## save commands to a script
27
- script = String.new('')
28
- script << "#{MAGICK_INPUT} \\\n"
52
+ min_lightness, max_lightness = lightness ? lightness : [0.0,0.0]
29
53
 
30
54
 
31
- width.times do |x|
32
- height.times do |y|
55
+ @img.width.times do |x|
56
+ @img.height.times do |y|
33
57
  color = @img[ x, y ]
34
58
 
35
- if color == 0 ## transparent
36
- if background ## change transparent to background
37
- color = background_color
38
- else
39
- next ## skip transparent
40
- end
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
41
67
  end
42
68
 
43
69
 
@@ -65,7 +91,6 @@ def spots( spot=10,
65
91
  # e.g. 0 becomes #00000000
66
92
  # and so on
67
93
  color_hex = Color.to_hex( color, include_alpha: true )
68
- script << "-fill '#{color_hex}' "
69
94
 
70
95
  cx_offset,
71
96
  cy_offset = if center ## randomize (offset off center +/-)
@@ -79,48 +104,40 @@ def spots( spot=10,
79
104
  cx = x*spot + x*spacing + cx_offset
80
105
  cy = y*spot + y*spacing + cx_offset
81
106
 
82
- px_offset = if radius ## randomize (radius +/-)
107
+ r = if radius ## randomize (radius +/-)
83
108
  min_radius + rand( max_radius-min_radius )
84
109
  else
85
110
  spot/2
86
111
  end
87
- px = cx + px_offset
88
- py = cy
89
112
 
113
+ cx += spot/2 if odd && (y % 2 == 1) ## add odd offset
90
114
 
91
- if odd && (y % 2 == 1) ## add odd offset
92
- cx += spot/2
93
- px += spot/2
94
- end
95
115
 
96
- ## circle
97
- ## give the center and any point on the perimeter (boundary)
98
- script << "-draw 'circle #{cx},#{cy},#{px},#{py}' \\\n"
116
+ v.circle( cx: cx, cy: cy, r: r, fill: color_hex)
99
117
  end
100
118
  end
119
+ v
120
+ end ## method spots_hidef
121
+ alias_method :spots_hd, :spots_hidef
101
122
 
102
- script << "-write #{MAGICK_OUTPUT}\n"
103
-
104
-
105
- ## use an empty image (canvas) with transparent background
106
- ## as magick input image
107
- canvas = Image.new( width*spot+(width-1)*spacing,
108
- height*spot+(height-1)*spacing )
109
- canvas.save( MAGICK_INPUT )
110
-
111
- ## note: save magick input first (see above) before save script
112
- ## will (auto-)create missing directories in path (if missing)
113
-
114
- File.open( MAGICK_SCRIPT, 'w:utf-8' ) do |f|
115
- f.write( script )
116
- end
117
123
 
124
+ def spots( spot=10,
125
+ spacing: 0,
126
+ center: nil,
127
+ radius: nil,
128
+ background: nil,
129
+ lightness: nil,
130
+ odd: false )
118
131
 
119
- MiniMagick::Tool::Magick.new do |magick|
120
- magick.script( MAGICK_SCRIPT )
121
- end
132
+ v = spots_hidef( spot,
133
+ spacing: spacing,
134
+ center: center,
135
+ radius: radius,
136
+ background: background,
137
+ lightness: lightness,
138
+ odd: odd )
122
139
 
123
- Image.read( MAGICK_OUTPUT )
140
+ v.to_image
124
141
  end
125
142
 
126
143
 
@@ -0,0 +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
@@ -0,0 +1,163 @@
1
+ module Pixelart
2
+
3
+
4
+ class Vector # holds a vector graphics image (in source)
5
+
6
+ class Shape; end
7
+ class Circle < Shape
8
+ def initialize( cx, cy, r, fill: )
9
+ @cx = cx
10
+ @cy = cy
11
+ @r = r
12
+ @fill = fill
13
+ end
14
+
15
+ def to_svg
16
+ %Q{<circle cx="#{@cx}" cy="#{@cy}" r="#{@r}" fill="#{@fill}" />}
17
+ end
18
+
19
+ def to_magick
20
+ ## circle
21
+ ## give the center and any point on the perimeter (boundary)
22
+ px = @cx+@r
23
+ py = @cy
24
+ "-fill '#{@fill}' -draw 'circle #{@cx},#{@cy},#{px},#{py}'"
25
+ end
26
+ end # class Circle
27
+
28
+ class Path < Shape
29
+ def initialize( fill:, stroke: )
30
+ @commands = []
31
+ @fill = fill
32
+ @stroke = stroke
33
+ end
34
+
35
+ def move_to( x, y ) ## add a move_to instruction
36
+ @commands << ['M', x, y]
37
+ self
38
+ end
39
+
40
+ def line_to( x, y )
41
+ @commands << ['L', x, y]
42
+ self
43
+ end
44
+
45
+ def line( *coords ) ## move_to/line_to all-in-one shortcut
46
+ ## todo/check - assert coords has at least two x/y pairs - why? why not?
47
+ move_to( *coords[0..1] )
48
+ coords[2..-1].each_slice( 2) do |coord|
49
+ line_to( *coord )
50
+ end
51
+ self
52
+ end
53
+
54
+
55
+
56
+ def to_svg
57
+ buf = %Q{<path style="stroke: #{@stroke}; fill: #{@fill || 'none'};" }
58
+ buf << %Q{d="}
59
+ last_command = ''
60
+ @commands.each_with_index do |command,i|
61
+ buf << " " if i > 0 # add space separator
62
+
63
+ ## "optimize" - that is, do not repead command if same as before
64
+ buf << command[0] if command[0] != last_command
65
+ buf << "#{command[1]} #{command[2]}"
66
+ last_command = command[0]
67
+ end
68
+
69
+ buf << %Q{"}
70
+ buf << "/>"
71
+ buf
72
+ end
73
+ end # class Path
74
+
75
+
76
+
77
+ def initialize( width, height, header: nil )
78
+ @width = width
79
+ @height = height
80
+
81
+ @header = header
82
+ @shapes = []
83
+ end
84
+
85
+ def circle( cx:, cy:, r:, fill: )
86
+ @shapes << Circle.new( cx, cy, r, fill: fill )
87
+ end
88
+
89
+ ## note: default stroke (color) to black (#000000) for now - why? why not?
90
+ def path( stroke: '#000000', fill: nil )
91
+ path = Path.new( stroke: stroke, fill: fill )
92
+ @shapes << path
93
+
94
+ path ## note: MUST return "inner" path shape for chaining "dsl-like" methods / commands
95
+ end
96
+
97
+
98
+
99
+ def to_image
100
+ ## use an empty image (canvas) with transparent background
101
+ ## as magick input image
102
+ canvas = Image.new( @width, @height )
103
+ canvas.save( MAGICK_INPUT )
104
+
105
+ ## note: magick command line might get way too long, thus,
106
+ ## save commands to a script
107
+ ## note: save magick input first (see above) before save script
108
+ ## will (auto-)create missing directories in path (if missing)
109
+
110
+ File.open( MAGICK_SCRIPT, 'w:utf-8' ) do |f|
111
+ f.write( "#{MAGICK_INPUT} \\\n" )
112
+ @shapes.each do |shape|
113
+ f.write( "#{shape.to_magick} \\\n" )
114
+ end
115
+ f.write( "-write #{MAGICK_OUTPUT}\n" )
116
+ end
117
+
118
+ MiniMagick::Tool::Magick.new do |magick|
119
+ magick.script( MAGICK_SCRIPT )
120
+ end
121
+
122
+ Image.read( MAGICK_OUTPUT )
123
+ end
124
+
125
+
126
+ def to_svg
127
+ buf = String.new('')
128
+
129
+ if @header
130
+ buf << "<!--\n"
131
+ ## auto-indent lines by five (5) spaces for now
132
+ @header.each_line do |line|
133
+ buf << " #{line}"
134
+ end
135
+ buf << "\n-->\n\n"
136
+ end
137
+
138
+ buf << %Q{<svg version="1.1" width="#{@width}" height="#{@height}" xmlns="http://www.w3.org/2000/svg">\n}
139
+ @shapes.each do |shape|
140
+ buf << " #{shape.to_svg}\n"
141
+ end
142
+ buf << "</svg>"
143
+ buf
144
+ end
145
+
146
+
147
+ def save( path, format: nil )
148
+ if format && format.downcase == 'png' ## support png with image magick
149
+ img = to_image
150
+ img.save( path )
151
+ else
152
+ # make sure outdir exits
153
+ outdir = File.dirname( path )
154
+ FileUtils.mkdir_p( outdir ) unless Dir.exist?( outdir )
155
+ File.open( path, 'w:utf-8' ) do |f|
156
+ f.write( to_svg )
157
+ end
158
+ end
159
+ end
160
+ alias_method :write, :save
161
+
162
+ end # class Vector
163
+ end # module Pixelart
@@ -2,8 +2,8 @@
2
2
  module Pixelart
3
3
 
4
4
  MAJOR = 1
5
- MINOR = 1
6
- PATCH = 0
5
+ MINOR = 2
6
+ PATCH = 2
7
7
  VERSION = [MAJOR,MINOR,PATCH].join('.')
8
8
 
9
9
  def self.version
data/lib/pixelart.rb CHANGED
@@ -8,3 +8,5 @@ require 'pixelart/base' # aka "strict(er)" version
8
8
  # make Image, Color, Palette8bit, etc top-level
9
9
  include Pixelart
10
10
 
11
+
12
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pixelart
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-24 00:00:00.000000000 Z
11
+ date: 2022-01-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chunky_png
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: csvreader
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rdoc
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -97,10 +111,13 @@ files:
97
111
  - lib/pixelart/misc.rb
98
112
  - lib/pixelart/palette.rb
99
113
  - lib/pixelart/pixelator.rb
114
+ - lib/pixelart/silhouette.rb
100
115
  - lib/pixelart/sketch.rb
101
116
  - lib/pixelart/spots.rb
117
+ - lib/pixelart/transparent.rb
118
+ - lib/pixelart/vector.rb
102
119
  - lib/pixelart/version.rb
103
- homepage: https://github.com/rubycoco/pixel
120
+ homepage: https://github.com/pixelartexchange/pixel
104
121
  licenses:
105
122
  - Public Domain
106
123
  metadata: {}