pixelart 0.1.5 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3022f23a6bfd66ef0e1c6f266fe2fd2ad24c802844be57737c2f202988e45292
4
- data.tar.gz: b8d11d3128aa897ef91f21dc727f3f9f713a94343142bbeb0cce228dfdba0e6b
3
+ metadata.gz: 066a13d4aff234657b8685f611168ed012fd6b949a292add28e7729f31c1bdc7
4
+ data.tar.gz: a7f748b8c246bb4c944da848baef19d4fdc6cd9c74ac96050c38aa907e680247
5
5
  SHA512:
6
- metadata.gz: '086d0b53c8ef6a949025fcd2cda50f505deae181e53bc6cc6241beec8470bbc9f6869a03f189cbf56c6706635e83e16a799dda4e383823dd032a1bb0029717c2'
7
- data.tar.gz: 3f577a57cd276d6a9eefdcf5374e5ea69e4f0f8f75cd69957098ec8c051258f70755c0883f8287bcf6e3768e35934bca4863d7ac41f55df7d1ae2395b4e12eed
6
+ metadata.gz: de3a072fd7dd9fe939340f1914fdeab6cc16dd5a2c25fb86548a3d5d89eb043b8d236dd62e2be86ac191bc0a5689eec2d3d6a3b465e08853a85cc285f394701a
7
+ data.tar.gz: 6fc5ffec090a5fbdc29b990812168d7716b4a563f3faffe8bd69ed09da70ca079af6334fa523cfdf3ed96f1228fd35842bc44d72139eeb6dc1b1d6299bf08b09
data/Manifest.txt CHANGED
@@ -5,8 +5,11 @@ Rakefile
5
5
  lib/pixelart.rb
6
6
  lib/pixelart/base.rb
7
7
  lib/pixelart/color.rb
8
+ lib/pixelart/composite.rb
8
9
  lib/pixelart/gradient.rb
9
10
  lib/pixelart/image.rb
11
+ lib/pixelart/led.rb
10
12
  lib/pixelart/misc.rb
11
13
  lib/pixelart/palette.rb
14
+ lib/pixelart/pixelator.rb
12
15
  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/cryptocopycats/mooncats](https://github.com/cryptocopycats/mooncats)
7
- * bugs :: [github.com/cryptocopycats/mooncats/issues](https://github.com/cryptocopycats/mooncats/issues)
6
+ * home :: [github.com/rubycoco/pixel](https://github.com/rubycoco/pixel)
7
+ * bugs :: [github.com/rubycoco/pixel/issues](https://github.com/rubycoco/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/cryptocopycats/mooncats/raw/master/pixelart/i/mooncat_white.png)
75
- ![](https://github.com/cryptocopycats/mooncats/raw/master/pixelart/i/mooncat_white-3x.png)
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)
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/cryptocopycats/mooncats/raw/master/pixelart/i/mooncat_black.png)
104
- ![](https://github.com/cryptocopycats/mooncats/raw/master/pixelart/i/mooncat_black-3x.png)
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)
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/cryptocopycats/mooncats/raw/master/pixelart/i/vader.png)
231
- ![](https://github.com/cryptocopycats/mooncats/raw/master/pixelart/i/vader5x.png)
230
+ ![](https://github.com/rubycoco/pixel/raw/master/pixelart/i/vader.png)
231
+ ![](https://github.com/rubycoco/pixel/raw/master/pixelart/i/vader5x.png)
232
232
 
233
233
 
234
234
 
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/cryptocopycats/mooncats' }
11
+ self.urls = { home: 'https://github.com/rubycoco/pixel' }
12
12
 
13
13
  self.author = 'Gerald Bauer'
14
14
  self.email = 'wwwmake@googlegroups.com'
data/lib/pixelart/base.rb CHANGED
@@ -14,9 +14,16 @@ require 'pixelart/color'
14
14
  require 'pixelart/gradient'
15
15
  require 'pixelart/palette'
16
16
  require 'pixelart/image'
17
+ require 'pixelart/composite'
18
+
19
+ require 'pixelart/pixelator'
17
20
 
18
21
  require 'pixelart/misc' ## misc helpers
19
22
 
23
+ require 'pixelart/led' ## (special) effects / filters
24
+
25
+
26
+
20
27
 
21
28
  ##########
22
29
  # add some spelling convenience variants
@@ -27,6 +34,8 @@ module Pixelart
27
34
 
28
35
  Palette256Image = Palette8BitImage = Palette8bitImage =
29
36
  ImagePalette256 = ImagePalette8Bit = ImagePalette8bit
37
+
38
+ CompositeImage = ImageComposite
30
39
  end
31
40
 
32
41
 
@@ -7,7 +7,6 @@ class Color
7
7
  WHITE = 0xffffffff # rgba(255,255,255,255)
8
8
 
9
9
 
10
-
11
10
  def self.parse( color )
12
11
  if color.is_a?( Integer ) ## e.g. assumes ChunkyPNG::Color.rgb() or such
13
12
  color ## pass through as is 1:1
@@ -0,0 +1,77 @@
1
+ module Pixelart
2
+
3
+ class ImageComposite < Image # check: (re)name to Collage, Sheet, Sprites, or such?
4
+
5
+ ## default tile width / height in pixel -- check: (re)name to sprite or such? why? why not?
6
+ TILE_WIDTH = 24
7
+ TILE_HEIGHT = 24
8
+
9
+
10
+ def initialize( *args, **kwargs )
11
+ @tile_width = kwargs[:width] || kwargs[:tile_width] || TILE_WIDTH
12
+ @tile_height = kwargs[:height] || kwargs[:tile_height] || TILE_HEIGHT
13
+
14
+ ## todo/fix: check type - args[0] is Image!!!
15
+ if args.size == 1 ## assume "copy" c'tor with passed in image
16
+ img = args[0] ## pass image through as-is
17
+
18
+ @tile_cols = img.width / @tile_width ## e.g. 2400/24 = 100
19
+ @tile_rows = img.height / @tile_height ## e.g. 2400/24 = 100
20
+ @tile_count = @tile_cols * @tile_rows ## ## 10000 = 100x100 (2400x2400 pixel)
21
+ elsif args.size == 2 || args.size == 0 ## cols, rows
22
+ ## todo/fix: check type - args[0] & args[1] is Integer!!!!!
23
+ ## todo/check - find a better name for cols/rows - why? why not?
24
+ @tile_cols = args[0] || 3
25
+ @tile_rows = args[1] || 3
26
+ @tile_count = 0 # (track) current index (of added images)
27
+
28
+ img = ChunkyPNG::Image.new( @tile_cols * @tile_width,
29
+ @tile_rows * @tile_height )
30
+ else
31
+ raise ArgumentError, "cols, rows or image arguments expected; got: #{args.inspect}"
32
+ end
33
+
34
+ puts " #{img.height}x#{img.width} (height x width)"
35
+
36
+ super( nil, nil, img )
37
+ end
38
+
39
+
40
+ def count() @tile_count; end
41
+ alias_method :size, :count ## add size alias (confusing if starting with 0?) - why? why not?
42
+
43
+ #####
44
+ # set / add tile
45
+
46
+ def add( image )
47
+ y, x = @tile_count.divmod( @tile_cols )
48
+
49
+ puts " [#{@tile_count}] @ (#{x}/#{y}) #{image.width}x#{image.height} (height x width)"
50
+
51
+ ## note: image.image - "unwrap" the "raw" ChunkyPNG::Image
52
+ @img.compose!( image.image, x*@tile_width, y*@tile_height )
53
+ @tile_count += 1
54
+ end
55
+ alias_method :<<, :add
56
+
57
+
58
+
59
+ ######
60
+ # get tile
61
+
62
+ def tile( index )
63
+ y, x = index.divmod( @tile_rows )
64
+ img = @img.crop( x*@tile_width, y*@tile_height, @tile_width, @tile_height )
65
+ Image.new( img.width, img.height, img ) ## wrap in pixelart image
66
+ end
67
+
68
+ def []( *args ) ## overload - why? why not?
69
+ if args.size == 1
70
+ index = args[0]
71
+ tile( index )
72
+ else
73
+ super ## e.g [x,y] --- get pixel
74
+ end
75
+ end
76
+ end # class ImageComposite
77
+ end # module Pixelart
@@ -9,7 +9,14 @@ def self.read( path ) ## convenience helper
9
9
  end
10
10
 
11
11
 
12
- def self.parse( pixels, colors: )
12
+
13
+ CHARS = '.@xo^~%*+=:' ## todo/check: rename to default chars or such? why? why not?
14
+
15
+ ## todo/check: support default chars encoding auto-of-the-box always
16
+ ## or require user-defined chars to be passed in - why? why not?
17
+ def self.parse( pixels, colors:, chars: CHARS )
18
+ has_keys = colors.is_a?(Hash) ## check if passed-in user-defined keys (via hash table)?
19
+
13
20
  colors = parse_colors( colors )
14
21
  pixels = parse_pixels( pixels )
15
22
 
@@ -20,7 +27,19 @@ def self.parse( pixels, colors: )
20
27
 
21
28
  pixels.each_with_index do |row,y|
22
29
  row.each_with_index do |color,x|
23
- pixel = colors[color]
30
+ pixel = if has_keys ## if passed-in user-defined keys check only the user-defined keys
31
+ colors[color]
32
+ else
33
+ ## try map ascii art char (.@xo etc.) to color index (0,1,2)
34
+ ## if no match found - fallback on assuming draw by number (0 1 2 etc.) encoding
35
+ pos = chars.index( color )
36
+ if pos
37
+ colors[ pos.to_s ]
38
+ else ## assume nil (not found)
39
+ colors[ color ]
40
+ end
41
+ end
42
+
24
43
  img[x,y] = pixel
25
44
  end # each row
26
45
  end # each data
@@ -31,6 +50,9 @@ end
31
50
 
32
51
 
33
52
  def initialize( width, height, initial=Color::TRANSPARENT )
53
+ ### todo/fix:
54
+ ## change params to *args only - why? why not?
55
+ ## make width/height optional if image passed in?
34
56
 
35
57
  if initial.is_a?( ChunkyPNG::Image )
36
58
  @img = initial
@@ -170,6 +192,9 @@ def []=( x, y, value ) @img[x,y]=value; end
170
192
 
171
193
  def pixels() @img.pixels; end
172
194
 
195
+ ### todo/check: add colors() e.g. @img.pixels.uniq - why? why not?
196
+
197
+
173
198
  ## return image ref - use a different name - why? why not?
174
199
  ## change to to_image - why? why not?
175
200
  def image() @img; end
@@ -183,10 +208,7 @@ def self.parse_pixels( pixels )
183
208
  data = []
184
209
  pixels.each_line do |line|
185
210
  line = line.strip
186
- if line.empty?
187
- puts "!! WARN: skipping empty line in pixel art source"
188
- next
189
- end
211
+ next if line.start_with?( '#' ) || line.empty? ## note: allow comments and empty lines
190
212
 
191
213
  ## note: allow multiple spaces or tabs to separate pixel codes
192
214
  ## e.g. o o o o o o o o o o o o dg lg w w lg w lg lg dg dg w w lg dg o o o o o o o o o o o
@@ -197,12 +219,13 @@ def self.parse_pixels( pixels )
197
219
  end
198
220
 
199
221
 
222
+
200
223
  def self.parse_colors( colors )
201
224
  if colors.is_a?( Array ) ## convenience shortcut
202
225
  ## note: always auto-add color 0 as pre-defined transparent - why? why not?
203
226
  h = { '0' => Color::TRANSPARENT }
204
227
  colors.each_with_index do |color, i|
205
- h[ (i+1).to_s ] = Color.parse( color )
228
+ h[ (i+1).to_s ] = Color.parse( color )
206
229
  end
207
230
  h
208
231
  else ## assume hash table with color map
@@ -215,7 +238,6 @@ def self.parse_colors( colors )
215
238
  end
216
239
 
217
240
 
218
-
219
241
  end # class Image
220
242
  end # module Pixelart
221
243
 
@@ -0,0 +1,37 @@
1
+ module Pixelart
2
+
3
+
4
+ class Image
5
+ def led( led=8, spacing: 2, round_corner: false )
6
+
7
+ width = @img.width*led + (@img.width-1)*spacing
8
+ height = @img.height*led + (@img.height-1)*spacing
9
+
10
+ puts " #{width}x#{height}"
11
+
12
+ img = Image.new( width, height, Color::BLACK )
13
+
14
+ @img.width.times do |x|
15
+ @img.height.times do |y|
16
+ pixel = @img[x,y]
17
+ pixel = Color::BLACK if pixel == Color::TRANSPARENT
18
+ led.times do |n|
19
+ led.times do |m|
20
+ ## round a little - drop all four corners for now
21
+ next if round_corner &&
22
+ [[0,0],[0,1],[1,0],[1,1],[0,2],[2,0],
23
+ [0,led-1],[0,led-2],[1,led-1],[1,led-2],[0,led-3],[2,led-1],
24
+ [led-1,0],[led-1,1],[led-2,0],[led-2,1],[led-1,2],[led-3,0],
25
+ [led-1,led-1],[led-1,led-2],[led-2,led-1],[led-2,led-2],[led-1,led-3],[led-3,led-1],
26
+ ].include?( [n,m] )
27
+ img[x*led+n + spacing*x,
28
+ y*led+m + spacing*y] = pixel
29
+ end
30
+ end
31
+ end
32
+ end
33
+ img
34
+ end
35
+ end # class Image
36
+ end # module Pixelart
37
+
data/lib/pixelart/misc.rb CHANGED
@@ -15,6 +15,9 @@ class ImagePalette8bit < Image # or use Palette256 alias?
15
15
  img = ChunkyPNG::Image.new( 32*size+(32-1)*spacing,
16
16
  8*size+(8-1)*spacing )
17
17
 
18
+
19
+ colors =colors.map {|color| Color.parse( color ) }
20
+
18
21
  colors.each_with_index do |color,i|
19
22
  y,x = i.divmod( 32 )
20
23
  if size > 1
@@ -32,6 +35,32 @@ class ImagePalette8bit < Image # or use Palette256 alias?
32
35
  super( img.width, img.height, img )
33
36
  end
34
37
  end # class ImagePalette8bit
38
+
39
+
40
+
41
+ class ImageColorBar < Image
42
+ ## make a color bar
43
+ ## keep auto-zoom 24x or such - why? why not?
44
+ def initialize( colors, size: 24 )
45
+ img = ChunkyPNG::Image.new( colors.size*size,
46
+ size,
47
+ ChunkyPNG::Color::WHITE ) # why? why not?
48
+
49
+ colors = colors.map {|color| Color.parse( color ) }
50
+
51
+ colors.each_with_index do |color,i|
52
+ size.times do |x|
53
+ size.times do |y|
54
+ img[x+size*i,y] = color
55
+ end
56
+ end
57
+ end
58
+
59
+ super( img.width, img.height, img )
60
+ end
61
+ end # class ImageColorBar
62
+
63
+
35
64
  end # module Pixelart
36
65
 
37
66
 
@@ -0,0 +1,165 @@
1
+ module Pixelart
2
+
3
+
4
+ class Pixelator # or use Minifier or such - rename - why? why not?
5
+
6
+ def initialize( img, width=24, height=24 )
7
+ @img = img.is_a?( Image ) ? img.image : img ## "unwrap" if Pixelart::Image
8
+ @width = width
9
+ @height = height
10
+
11
+ ## calculate pixel size / density / resolution
12
+ ## how many pixels per pixel?
13
+ @xsize, @xoverflow = img.width.divmod( width )
14
+ @ysize, @yoverflow = img.height.divmod( height )
15
+
16
+ puts "minify image size from (#{@img.width}x#{@img.height}) to (#{width}x#{height})"
17
+ puts " pixel size (#{@xsize}x#{@ysize}) - #{@xsize*@ysize} pixel(s) per pixel"
18
+ puts " overflow x: #{@xoverflow}, y: #{@yoverflow} pixel(s)" if @xoverflow > 0 || @yoverflow > 0
19
+ end
20
+
21
+
22
+ def grid( spacing: 10 )
23
+ width = @img.width + (@width-1)*spacing
24
+ height = @img.height + (@height-1)*spacing
25
+
26
+ img = ChunkyPNG::Image.new( width, height, ChunkyPNG::Color::WHITE )
27
+
28
+ @img.width.times do |x|
29
+ xpixel = x/@xsize
30
+ @img.height.times do |y|
31
+ ypixel = y/@ysize
32
+
33
+ ## clip overflow pixels
34
+ xpixel = @width-1 if xpixel >= @width
35
+ ypixel = @height-1 if ypixel >= @height
36
+
37
+ color = @img[x,y]
38
+ img[x + spacing*xpixel,
39
+ y + spacing*ypixel] = color
40
+ end
41
+ end
42
+
43
+ Image.new( img.width, img.height, img ) ## wrap in Pixelart::Image - why? why not?
44
+ end
45
+
46
+
47
+ # pixels by coordinates (x/y) with color statistics / usage
48
+ def pixels
49
+ @pixels ||= begin
50
+ pixels = []
51
+ @img.width.times do |x|
52
+ xpixel = x/@xsize
53
+ @img.height.times do |y|
54
+ ypixel = y/@ysize
55
+
56
+ ## skip/cut off overflow pixels
57
+ next if xpixel >= @width || ypixel >= @height
58
+
59
+ color = @img[x,y]
60
+ colors = pixels[xpixel+ypixel*@width] ||= Hash.new(0)
61
+ colors[ color ] += 1
62
+ end
63
+ end
64
+
65
+ ## sort pixel colors by usage / count (highest first)
66
+ pixels = pixels.map do |pixel|
67
+ pixel.sort do |l,r|
68
+ r[1] <=> l[1]
69
+ end.to_h
70
+ end
71
+ pixels
72
+ end
73
+ end
74
+
75
+ def pixel(x,y) pixels[x+y*@width]; end
76
+ alias_method :[], :pixel
77
+
78
+
79
+ def can_pixelate?( threshold: 50 )
80
+ # check if any pixel has NOT a color with a 50% majority?
81
+ count = 0
82
+ @width.times do |x|
83
+ @height.times do |y|
84
+ pixel = pixel( x, y )
85
+ sum = pixel.values.sum
86
+ color_count = pixel.values[0]
87
+
88
+ threshold_count = sum / (100/threshold)
89
+ if color_count < threshold_count
90
+ count += 1
91
+ puts "!! #{color_count} < #{threshold_count} (#{threshold}%)"
92
+ ## todo/check: stor warn in a public errors or warns array - why? why not?
93
+ puts "!! WARN #{count} - pixel (#{x}/#{y}) - no majority (#{threshold}%) color:"
94
+ pp pixel
95
+ end
96
+ end
97
+ end
98
+
99
+ count == 0 ## return true if not warnings found
100
+ end
101
+ alias_method :pixelate?, :can_pixelate?
102
+
103
+
104
+ def pixelate
105
+ img = ChunkyPNG::Image.new( @width, @height )
106
+
107
+ @width.times do |x|
108
+ @height.times do |y|
109
+ pixel = pixel( x, y )
110
+ color = pixel.keys[0]
111
+ img[x,y] = color
112
+ end
113
+ end
114
+
115
+ Image.new( img.width, img.height, img ) ## wrap in Pixelart::Image - why? why not?
116
+ end
117
+
118
+ def outline
119
+ ## create a two color outline (transparent and non-transparent color)
120
+ img = ChunkyPNG::Image.new( @width, @height )
121
+
122
+ @width.times do |x|
123
+ @height.times do |y|
124
+ pixel = pixel( x, y )
125
+ ## calculate pixel count for transparent and non-transparent parts
126
+ ## note:
127
+ ## also count all colors with alpha channel < 200 to transparent!!
128
+ transparent_count, color_count = pixel.reduce([0,0]) do |mem, (color,count)|
129
+ hsl = Color.to_hsl( color )
130
+ ## get alpha channel (transparency) for hsla
131
+ ## 0-255 max.
132
+ alpha = hsl[3]
133
+ if color == 0x00 || alpha < 200
134
+ mem[0] += count
135
+ else
136
+ mem[1] += count
137
+ end
138
+ mem
139
+ end
140
+
141
+ print "."
142
+ if transparent_count > 0 && color_count > 0
143
+ print "(#{x}/#{y}=>#{transparent_count}/#{color_count})"
144
+ end
145
+
146
+ ## todo/check:
147
+ ## warn if sum_transparent == sum_color
148
+ ## or within "threshold" e.g. below 55% or 58% or such - why? why not?
149
+ ## or add treshold as param to outline?
150
+ color = if transparent_count > color_count
151
+ 0x0
152
+ else
153
+ 0x0000ffff ## use blue for now
154
+ end
155
+
156
+ img[x,y] = color
157
+ end
158
+ end
159
+ print "\n"
160
+
161
+ Image.new( img.width, img.height, img ) ## wrap in Pixelart::Image - why? why not?
162
+ end
163
+ end # class Pixelator
164
+ end # module Pixelart
165
+
@@ -2,8 +2,8 @@
2
2
  module Pixelart
3
3
 
4
4
  MAJOR = 0
5
- MINOR = 1
6
- PATCH = 5
5
+ MINOR = 2
6
+ PATCH = 1
7
7
  VERSION = [MAJOR,MINOR,PATCH].join('.')
8
8
 
9
9
  def self.version
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: 0.1.5
4
+ version: 0.2.1
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-04-18 00:00:00.000000000 Z
11
+ date: 2021-05-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chunky_png
@@ -75,12 +75,15 @@ files:
75
75
  - lib/pixelart.rb
76
76
  - lib/pixelart/base.rb
77
77
  - lib/pixelart/color.rb
78
+ - lib/pixelart/composite.rb
78
79
  - lib/pixelart/gradient.rb
79
80
  - lib/pixelart/image.rb
81
+ - lib/pixelart/led.rb
80
82
  - lib/pixelart/misc.rb
81
83
  - lib/pixelart/palette.rb
84
+ - lib/pixelart/pixelator.rb
82
85
  - lib/pixelart/version.rb
83
- homepage: https://github.com/cryptocopycats/mooncats
86
+ homepage: https://github.com/rubycoco/pixel
84
87
  licenses:
85
88
  - Public Domain
86
89
  metadata: {}