pixelart 0.1.8 → 1.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3c72ac16513ce785c2bfcd63fe1d230950d03d597e0def19d4a35034b743d513
4
- data.tar.gz: dd3fcd6b2af8eaade1f9dc7bc7566af24ee3b5688d86363845cfc4794ee426d5
3
+ metadata.gz: c77200956faad2093e12cba99a8f8a3339941e612406701a795eecdcdd8248d8
4
+ data.tar.gz: d3dfbf4c9d278db95219b695dc55cea1b31debd8b5a08a20305135526d3618d1
5
5
  SHA512:
6
- metadata.gz: 4f299efeddddc2fe143595fbee1fa5b68fedd39f643da7700e25702398f5d3d3a5adc141268fa127dc669db476a41d64971b563997653ee1b2e0af8d418163eb
7
- data.tar.gz: e8cc7732cc24c04bcfb076f0ae48f088f2a48c4e83f23b897b194ae7def003effd8c08da8c0a7cde08fb55ea09ae2bf2ce0d9c017d38b759531e53881c5e7871
6
+ metadata.gz: db9abc2122d9727e2fee58c54913174983ff3dd03d2e2658c4b0a84d80114f0f482673d2b7e51fea61dbbb423f1df05eb5e027ba51d741ab86dc7e16d6f2eb72
7
+ data.tar.gz: 36c0733c3c5e15f18cca6787185eb2229fa8d7a98c3d037cf781295b8d32fc74be542a433de1504981afb984d9234730191dcf14443b3f614cd3dc9139d4fa7e
data/Manifest.txt CHANGED
@@ -5,10 +5,12 @@ 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
10
11
  lib/pixelart/led.rb
11
12
  lib/pixelart/misc.rb
12
13
  lib/pixelart/palette.rb
13
14
  lib/pixelart/pixelator.rb
15
+ lib/pixelart/sketch.rb
14
16
  lib/pixelart/version.rb
data/lib/pixelart/base.rb CHANGED
@@ -14,13 +14,14 @@ require 'pixelart/color'
14
14
  require 'pixelart/gradient'
15
15
  require 'pixelart/palette'
16
16
  require 'pixelart/image'
17
+ require 'pixelart/composite'
17
18
 
18
19
  require 'pixelart/pixelator'
19
20
 
20
21
  require 'pixelart/misc' ## misc helpers
21
22
 
22
- require 'pixelart/led' ## (special) effects / filters
23
-
23
+ require 'pixelart/led' ## (special) effects / filters
24
+ require 'pixelart/sketch'
24
25
 
25
26
 
26
27
 
@@ -33,6 +34,8 @@ module Pixelart
33
34
 
34
35
  Palette256Image = Palette8BitImage = Palette8bitImage =
35
36
  ImagePalette256 = ImagePalette8Bit = ImagePalette8bit
37
+
38
+ CompositeImage = ImageComposite
36
39
  end
37
40
 
38
41
 
@@ -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_cols )
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
@@ -73,6 +95,13 @@ def grayscale
73
95
  Image.new( img.width, img.height, img )
74
96
  end
75
97
 
98
+ def mirror
99
+ img = @img.mirror
100
+ Image.new( img.width, img.height, img )
101
+ end
102
+ alias_method :flip_vertically, :mirror
103
+
104
+
76
105
  ## add replace_colors alias too? - why? why not?
77
106
  def change_colors( color_map )
78
107
  color_map = _parse_color_map( color_map )
@@ -170,6 +199,9 @@ def []=( x, y, value ) @img[x,y]=value; end
170
199
 
171
200
  def pixels() @img.pixels; end
172
201
 
202
+ ### todo/check: add colors() e.g. @img.pixels.uniq - why? why not?
203
+
204
+
173
205
  ## return image ref - use a different name - why? why not?
174
206
  ## change to to_image - why? why not?
175
207
  def image() @img; end
@@ -183,10 +215,7 @@ def self.parse_pixels( pixels )
183
215
  data = []
184
216
  pixels.each_line do |line|
185
217
  line = line.strip
186
- if line.empty?
187
- puts "!! WARN: skipping empty line in pixel art source"
188
- next
189
- end
218
+ next if line.start_with?( '#' ) || line.empty? ## note: allow comments and empty lines
190
219
 
191
220
  ## note: allow multiple spaces or tabs to separate pixel codes
192
221
  ## 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 +226,13 @@ def self.parse_pixels( pixels )
197
226
  end
198
227
 
199
228
 
229
+
200
230
  def self.parse_colors( colors )
201
231
  if colors.is_a?( Array ) ## convenience shortcut
202
232
  ## note: always auto-add color 0 as pre-defined transparent - why? why not?
203
233
  h = { '0' => Color::TRANSPARENT }
204
234
  colors.each_with_index do |color, i|
205
- h[ (i+1).to_s ] = Color.parse( color )
235
+ h[ (i+1).to_s ] = Color.parse( color )
206
236
  end
207
237
  h
208
238
  else ## assume hash table with color map
@@ -215,7 +245,6 @@ def self.parse_colors( colors )
215
245
  end
216
246
 
217
247
 
218
-
219
248
  end # class Image
220
249
  end # module Pixelart
221
250
 
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
 
@@ -76,7 +76,7 @@ class Pixelator # or use Minifier or such - rename - why? why not?
76
76
  alias_method :[], :pixel
77
77
 
78
78
 
79
- def can_pixelate?
79
+ def can_pixelate?( threshold: 50 )
80
80
  # check if any pixel has NOT a color with a 50% majority?
81
81
  count = 0
82
82
  @width.times do |x|
@@ -84,10 +84,13 @@ class Pixelator # or use Minifier or such - rename - why? why not?
84
84
  pixel = pixel( x, y )
85
85
  sum = pixel.values.sum
86
86
  color_count = pixel.values[0]
87
- if color_count < (sum/2)
87
+
88
+ threshold_count = sum / (100/threshold)
89
+ if color_count < threshold_count
88
90
  count += 1
91
+ puts "!! #{color_count} < #{threshold_count} (#{threshold}%)"
89
92
  ## todo/check: stor warn in a public errors or warns array - why? why not?
90
- puts "!! WARN #{count} - pixel (#{x}/#{y}) - no majority (50%) color:"
93
+ puts "!! WARN #{count} - pixel (#{x}/#{y}) - no majority (#{threshold}%) color:"
91
94
  pp pixel
92
95
  end
93
96
  end
@@ -111,7 +114,52 @@ class Pixelator # or use Minifier or such - rename - why? why not?
111
114
 
112
115
  Image.new( img.width, img.height, img ) ## wrap in Pixelart::Image - why? why not?
113
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
114
163
  end # class Pixelator
115
164
  end # module Pixelart
116
165
 
117
-
@@ -0,0 +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,9 +1,9 @@
1
1
 
2
2
  module Pixelart
3
3
 
4
- MAJOR = 0
5
- MINOR = 1
6
- PATCH = 8
4
+ MAJOR = 1
5
+ MINOR = 0
6
+ PATCH = 0
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.8
4
+ version: 1.0.0
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-25 00:00:00.000000000 Z
11
+ date: 2021-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chunky_png
@@ -75,12 +75,14 @@ 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
80
81
  - lib/pixelart/led.rb
81
82
  - lib/pixelart/misc.rb
82
83
  - lib/pixelart/palette.rb
83
84
  - lib/pixelart/pixelator.rb
85
+ - lib/pixelart/sketch.rb
84
86
  - lib/pixelart/version.rb
85
87
  homepage: https://github.com/rubycoco/pixel
86
88
  licenses: