pixelart-characters 0.1.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 +7 -0
- data/CHANGELOG.md +3 -0
- data/Manifest.txt +6 -0
- data/README.md +337 -0
- data/Rakefile +29 -0
- data/lib/pixelart/characters.rb +174 -0
- data/lib/pixelart/characters/version.rb +26 -0
- metadata +103 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 199f065720b94d8445a3138c4ed903b2576f05d42f1c0f48c30a4286d64c4945
|
4
|
+
data.tar.gz: 50c3e59a290b5dad5469ba1b5d3322e42d747a41f0e7d24687dd8a62b21cd590
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e3cc3fafb8fb08ac5a7ffacd012b4cbbcfd100ea1337efc93bfabae2be05d890da389247b4450319e9f37d9444245aa251edcedf3ca201bbaf0b577e5d286260
|
7
|
+
data.tar.gz: bbd2f9090c70a79d15a41ceb91274ec480f04798e87a0925e6ee23c52f27d82633d66374b8bc1f8472ae433d7fca8e2eb48cebd9fce7b8ab60cf7474eb4262bb
|
data/CHANGELOG.md
ADDED
data/Manifest.txt
ADDED
data/README.md
ADDED
@@ -0,0 +1,337 @@
|
|
1
|
+
# Pixel Art Characters
|
2
|
+
|
3
|
+
pixelart-characters - generate pixel arts characters, algorithmically - paint by numbers - what about a new punk avatar portrait series? - yes, you can!
|
4
|
+
|
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)
|
8
|
+
* gem :: [rubygems.org/gems/pixelart-characters](https://rubygems.org/gems/pixelart-characters)
|
9
|
+
* rdoc :: [rubydoc.info/gems/pixelart-characters](http://rubydoc.info/gems/pixelart-characters)
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
## Usage
|
15
|
+
|
16
|
+
### Example №1 - 8-Bit Icon Series (20x20)
|
17
|
+
|
18
|
+
Let's try the 8-bit icon series with a 20x20 pixel art image set,
|
19
|
+
see [/design.punks/8bit](https://github.com/cryptopunksnotdead/design.punks#8-bit-icon-series-20x20).
|
20
|
+
|
21
|
+
|
22
|
+
Step 1: Map the pixel art images
|
23
|
+
(or designs in ascii text)
|
24
|
+
to a characters generation definition.
|
25
|
+
|
26
|
+
|
27
|
+
``` ruby
|
28
|
+
require 'pixelart/characters'
|
29
|
+
|
30
|
+
######
|
31
|
+
# skin tone colors
|
32
|
+
HUMAN_LIGHTER_BASE1 = '0xead9d9' # rgb(234 217 217) - hsl( 0° 29% 88%)
|
33
|
+
HUMAN_LIGHT_BASE1 = '0xdbb180' # rgb(219 177 128) - hsl( 32° 56% 68%)
|
34
|
+
HUMAN_DARK_BASE1 = '0xae8b61' # rgb(174 139 97) - hsl( 33° 32% 53%)
|
35
|
+
HUMAN_DARKER_BASE1 = '0x713f1d' # rgb(113 63 29) - hsl( 24° 59% 28%)
|
36
|
+
|
37
|
+
|
38
|
+
###############
|
39
|
+
# characters generation definition
|
40
|
+
CHARACTERS = {
|
41
|
+
'male' => {
|
42
|
+
'face' => [{ design: 'male', colors: [HUMAN_LIGHTER_BASE1] },
|
43
|
+
{ design: 'male', colors: [HUMAN_LIGHT_BASE1] },
|
44
|
+
{ design: 'male', colors: [HUMAN_DARK_BASE1] },
|
45
|
+
{ design: 'male', colors: [HUMAN_DARKER_BASE1] }],
|
46
|
+
'clothes' => (1..65).to_a,
|
47
|
+
'eye' => (1..32).to_a,
|
48
|
+
'mouth' => (1..26).to_a,
|
49
|
+
'hair' => (1..36).to_a,
|
50
|
+
},
|
51
|
+
'female' => {
|
52
|
+
'face' => [{ design: 'female', colors: [HUMAN_LIGHTER_BASE1] },
|
53
|
+
{ design: 'female', colors: [HUMAN_LIGHT_BASE1] },
|
54
|
+
{ design: 'female', colors: [HUMAN_DARK_BASE1] },
|
55
|
+
{ design: 'female', colors: [HUMAN_DARKER_BASE1] }],
|
56
|
+
'clothes' => (1..59).to_a,
|
57
|
+
'eye' => (1..53).to_a,
|
58
|
+
'mouth' => (1..17).to_a,
|
59
|
+
'hair' => (1..33).to_a,
|
60
|
+
}
|
61
|
+
}
|
62
|
+
```
|
63
|
+
|
64
|
+
|
65
|
+
Note: List all parts (such as face, clothes, eyes, etc.) that make up
|
66
|
+
a character in the paste order, that is,
|
67
|
+
the algo will generate an empty pixel image / canvas and than adds - or is that composes or pastes - one part after the other on top all the way from face to hair.
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
Let's set up the character generator (or is that artist?) by
|
72
|
+
passing in the characters definition and
|
73
|
+
the root directory housing all the the pixel art:
|
74
|
+
|
75
|
+
``` ruby
|
76
|
+
artist = Character.new( CHARACTERS,
|
77
|
+
dir: "./8bit" )
|
78
|
+
```
|
79
|
+
|
80
|
+
|
81
|
+
Let's generate some characters.
|
82
|
+
Let's start with a male using the part selection (1,1,1,1,1) - that is,
|
83
|
+
face #1, clothes #1, eye #1, mouth #1, and hair #1 -
|
84
|
+
and so on:
|
85
|
+
|
86
|
+
|
87
|
+
``` ruby
|
88
|
+
img = artist.generate( 'male', 1, 1, 1, 1, 1 )
|
89
|
+
img.save( '8bit-male1.png')
|
90
|
+
img.zoom(4).save( '8bit-male1x4.png')
|
91
|
+
|
92
|
+
img = artist.generate( 'male', 2, 2, 2, 2, 2 )
|
93
|
+
img.save( '8bit-male2.png')
|
94
|
+
img.zoom(4).save( '8bit-male2x4.png')
|
95
|
+
|
96
|
+
img = artist.generate( 'male', 3, 3, 3, 3, 3 )
|
97
|
+
img.save( '8bit-male3.png')
|
98
|
+
img.zoom(4).save( '8bit-male3x4.png')
|
99
|
+
|
100
|
+
img = artist.generate( 'male', 4, 4, 4, 4, 4 )
|
101
|
+
img.save( '8bit-male4.png')
|
102
|
+
img.zoom(4).save( '8bit-male4x4.png')
|
103
|
+
|
104
|
+
|
105
|
+
img = artist.generate( 'female', 1, 1, 1, 1, 1 )
|
106
|
+
img.save( '8bit-female1.png')
|
107
|
+
img.zoom(4).save( '8bit-female1x4.png')
|
108
|
+
|
109
|
+
img = artist.generate( 'female', 2, 2, 2, 2, 2 )
|
110
|
+
img.save( '8bit-female2.png')
|
111
|
+
img.zoom(4).save( '8bit-female2x4.png')
|
112
|
+
|
113
|
+
img = artist.generate( 'female', 3, 3, 3, 3, 3 )
|
114
|
+
img.save( '8bit-female3.png')
|
115
|
+
img.zoom(4).save( '8bit-female3x4.png')
|
116
|
+
|
117
|
+
img = artist.generate( 'female', 4, 4, 4, 4, 4 )
|
118
|
+
img.save( '8bit-female4.png')
|
119
|
+
img.zoom(4).save( '8bit-female4x4.png')
|
120
|
+
```
|
121
|
+
|
122
|
+
Voila!
|
123
|
+
|
124
|
+

|
125
|
+

|
126
|
+

|
127
|
+

|
128
|
+

|
129
|
+

|
130
|
+

|
131
|
+

|
132
|
+
|
133
|
+
4x
|
134
|
+
|
135
|
+

|
136
|
+

|
137
|
+

|
138
|
+

|
139
|
+

|
140
|
+

|
141
|
+

|
142
|
+

|
143
|
+
|
144
|
+
|
145
|
+
|
146
|
+
Let the artist do the painting, that is, let the computer fill in the numbers
|
147
|
+
with a random lottery.
|
148
|
+
|
149
|
+
``` ruby
|
150
|
+
img = artist.random( 'male' )
|
151
|
+
img.save( '8bit-male-random1.png')
|
152
|
+
img.zoom(4).save( '8bit-male-random1x4.png')
|
153
|
+
|
154
|
+
img = artist.random( 'female' )
|
155
|
+
img.save( '8bit-female-random1.png')
|
156
|
+
img.zoom(4).save( '8bit-female-random1x4.png')
|
157
|
+
|
158
|
+
img = artist.random
|
159
|
+
img.save( '8bit-random1.png')
|
160
|
+
img.zoom(4).save( '8bit-random1x4.png')
|
161
|
+
|
162
|
+
img = artist.random
|
163
|
+
img.save( '8bit-random2.png')
|
164
|
+
img.zoom(4).save( '8bit-random2x4.png')
|
165
|
+
```
|
166
|
+
|
167
|
+
Voila!
|
168
|
+
|
169
|
+

|
170
|
+

|
171
|
+

|
172
|
+

|
173
|
+
|
174
|
+
4x
|
175
|
+
|
176
|
+

|
177
|
+

|
178
|
+

|
179
|
+

|
180
|
+
|
181
|
+
|
182
|
+
|
183
|
+
|
184
|
+
### Example №2 - "SubstraPunks" - CryptoPunks, Polkadot Edition (32x32)
|
185
|
+
|
186
|
+
|
187
|
+
Let's try the "SubstraPunks", that is, the CryptoPunks, Polkadot Edition series with a 32x32 pixel art image set,
|
188
|
+
see [Inside the Punk Art Machinery - How To Generate 10 000 Punks (and Punkettes), Algorithmically - Paint by Numbers](https://github.com/cryptopunksnotdead/programming-cryptopunks/blob/master/03_generate.md) in the Programming CryptoPunks & Copypastas book(let).
|
189
|
+
|
190
|
+
|
191
|
+
Step 1: Map the pixel art images
|
192
|
+
(or designs in ascii text)
|
193
|
+
to a characters generation definition.
|
194
|
+
|
195
|
+
|
196
|
+
``` ruby
|
197
|
+
PARTS = {
|
198
|
+
face: { required: true,
|
199
|
+
attributes: [['', 'u'],
|
200
|
+
['', 'u']] },
|
201
|
+
mouth: { required: true,
|
202
|
+
attributes: [['Black Lipstick', 'f'],
|
203
|
+
['Red Lipstick', 'f'],
|
204
|
+
['Smile', 'u'],
|
205
|
+
['', 'u'],
|
206
|
+
['Teeth Smile', 'm'],
|
207
|
+
['Purple Lipstick', 'f']] },
|
208
|
+
nose: { required: true,
|
209
|
+
attributes: [['', 'u'],
|
210
|
+
['Nose Ring', 'u']] },
|
211
|
+
eyes: { required: true,
|
212
|
+
attributes: [['', 'u'],
|
213
|
+
['Asian Eyes', 'u'],
|
214
|
+
['Sun Glasses', 'u'],
|
215
|
+
['Red Glasses', 'u'],
|
216
|
+
['Round Eyes', 'u']] },
|
217
|
+
ears: { required: true,
|
218
|
+
attributes: [['', 'u'],
|
219
|
+
['Left Earring', 'u'],
|
220
|
+
['Right Earring', 'u'],
|
221
|
+
['Two Earrings', 'u']] },
|
222
|
+
beard: { required: false,
|
223
|
+
attributes: [['Brown Beard', 'm'],
|
224
|
+
['Mustache-Beard', 'm'],
|
225
|
+
['Mustache', 'm'],
|
226
|
+
['Regular Beard', 'm']] },
|
227
|
+
hair: { required: false,
|
228
|
+
attributes: [['Up Hair', 'm'],
|
229
|
+
['Down Hair', 'u'],
|
230
|
+
['Mahawk', 'u'],
|
231
|
+
['Red Mahawk', 'u'],
|
232
|
+
['Orange Hair', 'u'],
|
233
|
+
['Bubble Hair', 'm'],
|
234
|
+
['Emo Hair', 'u'],
|
235
|
+
['Thin Hair', 'm'],
|
236
|
+
['Bald', 'm'],
|
237
|
+
['Blonde Hair', 'f']] }
|
238
|
+
}
|
239
|
+
```
|
240
|
+
|
241
|
+
|
242
|
+
Note: This characters generation definition uses the "compact" format
|
243
|
+
with "auto-implied" male and female types and
|
244
|
+
using the m/f/u type flags -
|
245
|
+
standing in for male, female and both (that is, unisex).
|
246
|
+
|
247
|
+
|
248
|
+
Let's set up the character generator (or is that artist?) by
|
249
|
+
passing in the characters definition and
|
250
|
+
the root directory housing all the the pixel art:
|
251
|
+
|
252
|
+
``` ruby
|
253
|
+
artist = Character.new( PARTS, dir: "./parts",
|
254
|
+
format: 'compact' )
|
255
|
+
```
|
256
|
+
|
257
|
+
|
258
|
+
Let's generate some characters.
|
259
|
+
|
260
|
+
``` ruby
|
261
|
+
img = artist.generate( 'female', 2, 2, 2, 3, 1, 6 )
|
262
|
+
img.save( 'polka-female.png')
|
263
|
+
img.zoom(3).save( 'polka-femalex3.png')
|
264
|
+
|
265
|
+
img = artist.generate( 'male', 1, 3, 2, 3, 1, 1, 5 )
|
266
|
+
img.save( 'polka-male.png')
|
267
|
+
img.zoom(3).save( 'polka-malex3.png')
|
268
|
+
```
|
269
|
+
|
270
|
+
Voila!
|
271
|
+
|
272
|
+

|
273
|
+

|
274
|
+
|
275
|
+

|
276
|
+

|
277
|
+
|
278
|
+
|
279
|
+
And with a random lottery.
|
280
|
+
|
281
|
+
``` ruby
|
282
|
+
img = artist.random( 'female' )
|
283
|
+
img.save( 'polka-female-random.png')
|
284
|
+
img.zoom(3).save( 'polka-female-randomx3.png')
|
285
|
+
|
286
|
+
img = artist.random( 'male' )
|
287
|
+
img.save( 'polka-male-random.png')
|
288
|
+
img.zoom(3).save( 'polka-male-randomx3.png')
|
289
|
+
|
290
|
+
img = artist.random
|
291
|
+
img.save( 'polka-random1.png')
|
292
|
+
img.zoom(3).save( 'polka-random1x3.png')
|
293
|
+
|
294
|
+
img = artist.random
|
295
|
+
img.save( 'polka-random2.png')
|
296
|
+
img.zoom(3).save( 'polka-random2x3.png')
|
297
|
+
|
298
|
+
img = artist.random
|
299
|
+
img.save( 'polka-random3.png')
|
300
|
+
img.zoom(3).save( 'polka-random3x3.png')
|
301
|
+
```
|
302
|
+
|
303
|
+

|
304
|
+

|
305
|
+

|
306
|
+

|
307
|
+

|
308
|
+
|
309
|
+

|
310
|
+

|
311
|
+

|
312
|
+

|
313
|
+

|
314
|
+
|
315
|
+
|
316
|
+
That's it.
|
317
|
+
|
318
|
+
|
319
|
+
|
320
|
+
## Install
|
321
|
+
|
322
|
+
Just install the gem:
|
323
|
+
|
324
|
+
$ gem install pixelart-characters
|
325
|
+
|
326
|
+
|
327
|
+
## License
|
328
|
+
|
329
|
+
The scripts are dedicated to the public domain.
|
330
|
+
Use it as you please with no restrictions whatsoever.
|
331
|
+
|
332
|
+
|
333
|
+
|
334
|
+
|
335
|
+
## Questions? Comments?
|
336
|
+
|
337
|
+
Post them on the [CryptoPunksDev reddit](https://old.reddit.com/r/CryptoPunksDev). Thanks.
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'hoe'
|
2
|
+
require './lib/pixelart/characters/version.rb'
|
3
|
+
|
4
|
+
Hoe.spec 'pixelart-characters' do
|
5
|
+
|
6
|
+
self.version = Pixelart::Module::Characters::VERSION
|
7
|
+
|
8
|
+
self.summary = "pixelart-characters - generate pixel arts characters, algorithmically - paint by numbers - what about a new punk avatar portrait series? - yes, you can!"
|
9
|
+
self.description = summary
|
10
|
+
|
11
|
+
self.urls = { home: 'https://github.com/rubycoco/pixel' }
|
12
|
+
|
13
|
+
self.author = 'Gerald Bauer'
|
14
|
+
self.email = 'wwwmake@googlegroups.com'
|
15
|
+
|
16
|
+
# switch extension to .markdown for gihub formatting
|
17
|
+
self.readme_file = 'README.md'
|
18
|
+
self.history_file = 'CHANGELOG.md'
|
19
|
+
|
20
|
+
self.extra_deps = [
|
21
|
+
['pixelart'],
|
22
|
+
]
|
23
|
+
|
24
|
+
self.licenses = ['Public Domain']
|
25
|
+
|
26
|
+
self.spec_extras = {
|
27
|
+
required_ruby_version: '>= 2.3'
|
28
|
+
}
|
29
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
require 'pixelart/base'
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
## our own code
|
6
|
+
require 'pixelart/characters/version' # note: let version always go first
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
module Pixelart
|
11
|
+
class Character ## todo/check: rename to Generator or Artist or such? why? why not?
|
12
|
+
|
13
|
+
|
14
|
+
def self.build( chars, format=nil )
|
15
|
+
## try to unify characters format
|
16
|
+
## format 1 - "compact" style
|
17
|
+
## check for attributes with "type flags" e.g.
|
18
|
+
## face: { required: true,
|
19
|
+
## attributes: [['', 'u'],
|
20
|
+
## ['', 'u']] },
|
21
|
+
|
22
|
+
if format && [:compact].include?( format.downcase.to_sym )
|
23
|
+
## note: assumes male/female types
|
24
|
+
chars_by_type = { 'male' => {},
|
25
|
+
'female' => {},
|
26
|
+
}
|
27
|
+
m = chars_by_type['male'] ## access shortcuts
|
28
|
+
f = chars_by_type['female']
|
29
|
+
|
30
|
+
## mouth: { attributes: [['Black Lipstick', 'f'],
|
31
|
+
## ['Red Lipstick', 'f'],
|
32
|
+
## ['Smile', 'u'],
|
33
|
+
## ['', 'u'],
|
34
|
+
## ['Teeth Smile', 'm'],
|
35
|
+
## ['Purple Lipstick', 'f']]}
|
36
|
+
chars.each do |part_key, part|
|
37
|
+
## always convert keys to string for now - why? why not?
|
38
|
+
part_key = part_key.to_s
|
39
|
+
|
40
|
+
## todo/fix: add/pass along required: true/false too - skiped for now
|
41
|
+
## add at the end? if some attributes present? why? why not?
|
42
|
+
part[:attributes].each_with_index do |rec,i|
|
43
|
+
attr_name = rec[0]
|
44
|
+
type_flag = rec[1] ## char type flag e.g. m/f/u (male/female/unisex)
|
45
|
+
|
46
|
+
attribute = {
|
47
|
+
## todo/check: rename path to id - why? why not? (for now its basename w/o extension etc.)
|
48
|
+
path: "#{part_key}/#{part_key}#{i+1}" ## map to filename (note: w/o extension for now)
|
49
|
+
}
|
50
|
+
attribute[:name] = attr_name if attr_name && attr_name.size > 0
|
51
|
+
|
52
|
+
## note: only add part "on demand", that is, if no attributes for m/f than no part too
|
53
|
+
if type_flag == 'm' || type_flag == 'u'
|
54
|
+
m_attributes = ( m[part_key] ||= { attributes: [] } )[:attributes]
|
55
|
+
m_attributes << attribute
|
56
|
+
end
|
57
|
+
|
58
|
+
if type_flag == 'f' || type_flag == 'u'
|
59
|
+
f_attributes = ( f[part_key] ||= { attributes: [] } )[:attributes]
|
60
|
+
f_attributes << attribute
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
puts "(normalized) characters spec:"
|
66
|
+
pp chars_by_type
|
67
|
+
|
68
|
+
chars_by_type
|
69
|
+
else ## pass-through for now
|
70
|
+
chars
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
def initialize( chars, dir: '.',
|
77
|
+
format: nil )
|
78
|
+
## todo/check: (re)name format param to style or ? - find a better name - why? why not?
|
79
|
+
|
80
|
+
@chars = self.class.build( chars, format ) ## build ("unify/normalize") characters spec
|
81
|
+
|
82
|
+
@rootdir = dir
|
83
|
+
end
|
84
|
+
|
85
|
+
def types() @chars.keys; end
|
86
|
+
|
87
|
+
|
88
|
+
def random( type=nil )
|
89
|
+
type = types[ rand( types.size ) ] if type.nil?
|
90
|
+
|
91
|
+
character = @chars[ type ]
|
92
|
+
|
93
|
+
nums = []
|
94
|
+
character.each do |_, part|
|
95
|
+
attributes_size = if part.is_a?( Hash )
|
96
|
+
part[:attributes].size
|
97
|
+
else ## assume array - "inline" compact attribute format
|
98
|
+
part.size
|
99
|
+
end
|
100
|
+
|
101
|
+
## todo/fix: check for part optional (true/false) ?
|
102
|
+
## if optional possible (start rand at 0 NOT 1) - why? why not?
|
103
|
+
nums << rand( 1..attributes_size )
|
104
|
+
end
|
105
|
+
generate( type, *nums )
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
## todo/fix: add alternate support for **kwargs
|
110
|
+
## instead of positional number list - why? why not?
|
111
|
+
def generate( type, *args )
|
112
|
+
puts "==> generate >#{type}< - with #{args.size} part(s) #{args.inspect}"
|
113
|
+
|
114
|
+
character = @chars[ type ]
|
115
|
+
|
116
|
+
img = nil ## (by default) auto-derive width x height dimension from first image
|
117
|
+
|
118
|
+
character.each_with_index do |(part_key, part),i|
|
119
|
+
num = args[i]
|
120
|
+
|
121
|
+
## todo/check - double check if part required set to false - why? why not?
|
122
|
+
next if num == 0 ## note: skip part if index is 0!!!
|
123
|
+
|
124
|
+
attributes = if part.is_a?( Hash )
|
125
|
+
part[:attributes]
|
126
|
+
else ## assume array - "inline" compact attribute format
|
127
|
+
part
|
128
|
+
end
|
129
|
+
|
130
|
+
attribute = attributes[ num-1 ] ## note: num starts counting at 1 (sub 1 for zero-based array index)
|
131
|
+
raise ArgumentError, "no >#{part_key}< part found for index #{num}; sorry" if attribute.nil?
|
132
|
+
|
133
|
+
print "#{i} #{part_key} => #{num}"
|
134
|
+
print " - #{attribute[:name]}" if attribute.is_a?( Hash ) && attribute.has_key?( :name )
|
135
|
+
print "\n"
|
136
|
+
|
137
|
+
|
138
|
+
img_part = if attribute.is_a?( Integer ) ## assume filename with num (as .png)
|
139
|
+
path = "#{@rootdir}/#{type}/#{part_key}/#{part_key}#{num}.png"
|
140
|
+
img_part = Image.read( path )
|
141
|
+
elsif attribute.is_a?( Hash )
|
142
|
+
if attribute.has_key?( :design )
|
143
|
+
path = "#{@rootdir}/#{attribute[:design]}.txt"
|
144
|
+
txt = File.open( path, 'r:utf-8') {|f| f.read }
|
145
|
+
img_part = Image.parse( txt, colors: attribute[:colors] )
|
146
|
+
else ## assume for now has key :path
|
147
|
+
path = "#{@rootdir}/#{attribute[:path]}.png"
|
148
|
+
img_part = Image.read( path )
|
149
|
+
end
|
150
|
+
else
|
151
|
+
puts "!! ERROR:"
|
152
|
+
pp part
|
153
|
+
raise ArgumentError, "unknown part data type; expected Integer|Hash"
|
154
|
+
end
|
155
|
+
## note: if (very) first part - auto-create empty image with size/dimensions from part
|
156
|
+
img = Image.new( img_part.width, img_part.height ) if i==0
|
157
|
+
img.compose!( img_part )
|
158
|
+
end
|
159
|
+
|
160
|
+
img
|
161
|
+
end
|
162
|
+
|
163
|
+
end # class Character
|
164
|
+
end # module Pixelart
|
165
|
+
|
166
|
+
|
167
|
+
|
168
|
+
###
|
169
|
+
# note: for convenience auto include Pixelart namespace!!! - why? why not?
|
170
|
+
include Pixelart
|
171
|
+
|
172
|
+
|
173
|
+
puts Pixelart::Module::Characters.banner # say hello
|
174
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
module Pixelart
|
3
|
+
module Module
|
4
|
+
module Characters
|
5
|
+
|
6
|
+
MAJOR = 0
|
7
|
+
MINOR = 1
|
8
|
+
PATCH = 0
|
9
|
+
VERSION = [MAJOR,MINOR,PATCH].join('.')
|
10
|
+
|
11
|
+
def self.version
|
12
|
+
VERSION
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.banner
|
16
|
+
"pixelart-characters/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}] in (#{root})"
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.root
|
20
|
+
File.expand_path( File.dirname(File.dirname(File.dirname(File.dirname(__FILE__)))) )
|
21
|
+
end
|
22
|
+
|
23
|
+
end # module Characters
|
24
|
+
end # module Module
|
25
|
+
end # module Pixelart
|
26
|
+
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pixelart-characters
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gerald Bauer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-05-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: pixelart
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rdoc
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.0'
|
34
|
+
- - "<"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '7'
|
37
|
+
type: :development
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '4.0'
|
44
|
+
- - "<"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '7'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: hoe
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '3.22'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '3.22'
|
61
|
+
description: pixelart-characters - generate pixel arts characters, algorithmically
|
62
|
+
- paint by numbers - what about a new punk avatar portrait series? - yes, you can!
|
63
|
+
email: wwwmake@googlegroups.com
|
64
|
+
executables: []
|
65
|
+
extensions: []
|
66
|
+
extra_rdoc_files:
|
67
|
+
- CHANGELOG.md
|
68
|
+
- Manifest.txt
|
69
|
+
- README.md
|
70
|
+
files:
|
71
|
+
- CHANGELOG.md
|
72
|
+
- Manifest.txt
|
73
|
+
- README.md
|
74
|
+
- Rakefile
|
75
|
+
- lib/pixelart/characters.rb
|
76
|
+
- lib/pixelart/characters/version.rb
|
77
|
+
homepage: https://github.com/rubycoco/pixel
|
78
|
+
licenses:
|
79
|
+
- Public Domain
|
80
|
+
metadata: {}
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options:
|
83
|
+
- "--main"
|
84
|
+
- README.md
|
85
|
+
require_paths:
|
86
|
+
- lib
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '2.3'
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
requirements: []
|
98
|
+
rubygems_version: 3.1.4
|
99
|
+
signing_key:
|
100
|
+
specification_version: 4
|
101
|
+
summary: pixelart-characters - generate pixel arts characters, algorithmically - paint
|
102
|
+
by numbers - what about a new punk avatar portrait series? - yes, you can!
|
103
|
+
test_files: []
|