mooncats 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Manifest.txt +1 -0
- data/lib/mooncats.rb +8 -0
- data/lib/mooncats/composite.rb +1 -1
- data/lib/mooncats/design.rb +92 -0
- data/lib/mooncats/image.rb +5 -136
- data/lib/mooncats/structs.rb +48 -22
- data/lib/mooncats/version.rb +2 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf22f607c257a0cef8877f44594782f1c6f704a9c580c01af96a39d49f985209
|
4
|
+
data.tar.gz: f6b10d2506c5b3dc05477ad4d8ba18c24eada0382cbcc29fdbfa0c572a04c892
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4e20d5394cd29624a64d0b7a830fbf7bc0b0890c021a25c077a7c51771600b9d7187220abd2e76c5a94b2f1a50d66fae040727950fca4be859db8a821791082a
|
7
|
+
data.tar.gz: 6028eadc62a9861e3e9c5be6215ec0bb142701cffd15e88d681ce4c30cfc137df4ee102f9b09de0c41f9d1a4715771d631d488a1b49326a8fba96bf211615e08
|
data/Manifest.txt
CHANGED
data/lib/mooncats.rb
CHANGED
@@ -12,6 +12,7 @@ require 'optparse'
|
|
12
12
|
require 'mooncats/version' # note: let version always go first
|
13
13
|
require 'mooncats/designs'
|
14
14
|
require 'mooncats/structs'
|
15
|
+
require 'mooncats/design'
|
15
16
|
require 'mooncats/image'
|
16
17
|
require 'mooncats/composite'
|
17
18
|
require 'mooncats/dataset'
|
@@ -93,4 +94,11 @@ module Mooncats
|
|
93
94
|
MoonCats = Mooncats
|
94
95
|
|
95
96
|
|
97
|
+
|
98
|
+
|
99
|
+
###
|
100
|
+
# note: for convenience auto include Pixelart namespace!!! - why? why not?
|
101
|
+
include Pixelart
|
102
|
+
|
103
|
+
|
96
104
|
puts Mooncats.banner # say hello
|
data/lib/mooncats/composite.rb
CHANGED
@@ -10,7 +10,7 @@ CANVAS_HEIGHT = 24
|
|
10
10
|
def initialize( cols=100, rows=255 )
|
11
11
|
@composite = ChunkyPNG::Image.new( cols*CANVAS_WIDTH,
|
12
12
|
rows*CANVAS_HEIGHT,
|
13
|
-
ChunkyPNG::Color::
|
13
|
+
ChunkyPNG::Color::TRANSPARENT ) # why? why not? - use TRANSPARENT (is default?)
|
14
14
|
|
15
15
|
## todo/check - find a better name for cols/rows - why? why not?
|
16
16
|
@cols = cols
|
@@ -0,0 +1,92 @@
|
|
1
|
+
|
2
|
+
module Mooncats
|
3
|
+
|
4
|
+
|
5
|
+
class Design
|
6
|
+
def self.find( num ) ## pass in design index number (0 to 127)
|
7
|
+
## todo: add cache (memoize) - why? why not?
|
8
|
+
design = parse( DESIGNS[ num ] )
|
9
|
+
|
10
|
+
puts " design ##{num} (#{design.width}x#{design.height})"
|
11
|
+
## pp design.data
|
12
|
+
## puts
|
13
|
+
|
14
|
+
design
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
def self.parse( str )
|
20
|
+
## support original "classic" compact single-line format
|
21
|
+
## e.g. 00011111100000000.01113333310000000.13533333331110000....
|
22
|
+
## note: this format needs to get rotated by 90 degree!!!
|
23
|
+
if str.start_with?( /[0-5]+\.[0-5]+\.[0-5]+/ ) ## quick (and dirty) heuristic check
|
24
|
+
data = str.split('.')
|
25
|
+
|
26
|
+
## note: map colors encoded as a string to an array of integers - why? why not?
|
27
|
+
## e.g. "00011111133344411"
|
28
|
+
## =>
|
29
|
+
## [0,0,0,1,1,1,1,1,1,3,3,3,4,4,4,1,1]
|
30
|
+
data = data.map do |row|
|
31
|
+
row.chars.map do |color|
|
32
|
+
color.to_i
|
33
|
+
end
|
34
|
+
end
|
35
|
+
data = data.transpose ## note: rotate by 90 degree!!!!!
|
36
|
+
else ## assume "modern" pixelart format
|
37
|
+
## todo/check: delegate to pixelart parse or such - why? why not?
|
38
|
+
|
39
|
+
data = []
|
40
|
+
str.each_line do |line|
|
41
|
+
line = line.strip
|
42
|
+
next if line.empty? ## skipping empty line in pixel art source
|
43
|
+
next if line.start_with?( '#' ) ## skipping comment line in pixel art source
|
44
|
+
|
45
|
+
## note: allow multiple spaces or tabs to separate pixel codes
|
46
|
+
data << line.split( /[ \t]+/)
|
47
|
+
end
|
48
|
+
## todo/check: change to use strings (instead of nummbers) in the future?
|
49
|
+
## why? why not? stay "compatible" to pixel art format/machinery?
|
50
|
+
data = data.map do |row|
|
51
|
+
row.map do |color|
|
52
|
+
color.to_i
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
new( data )
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def initialize( data )
|
61
|
+
@data = data
|
62
|
+
end
|
63
|
+
|
64
|
+
def width
|
65
|
+
## todo/check: use/find max - why? why not? lets you you used "unbalanced" / shortcut lines too
|
66
|
+
@data[0].size
|
67
|
+
end
|
68
|
+
def height() @data.size; end
|
69
|
+
|
70
|
+
|
71
|
+
def each_with_index( &blk )
|
72
|
+
@data.each_with_index { |row, y| blk.call( row, y ) }
|
73
|
+
end
|
74
|
+
def each( &blk )
|
75
|
+
@data.each { |row| blk.call( row ) }
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
|
80
|
+
def to_txt
|
81
|
+
buf = String.new('')
|
82
|
+
|
83
|
+
@data.each do |row|
|
84
|
+
buf << row.join( ' ' )
|
85
|
+
buf << "\n"
|
86
|
+
end
|
87
|
+
buf
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
end # class Design
|
92
|
+
end # module Mooncats
|
data/lib/mooncats/image.rb
CHANGED
@@ -2,33 +2,6 @@
|
|
2
2
|
module Mooncats
|
3
3
|
|
4
4
|
|
5
|
-
|
6
|
-
###
|
7
|
-
## todo/fix/cleanup - (re)use pixelart color helpers? possible? why? why not?
|
8
|
-
|
9
|
-
class Color ## convenience helper to "abstract" ChunkyPNG usage away in "outside" (not internal) sample code
|
10
|
-
def self.to_hex(color, include_alpha: false)
|
11
|
-
if include_alpha
|
12
|
-
'#%08x' % color
|
13
|
-
else
|
14
|
-
'#%06x' % [color >> 8]
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.rgb_to_hsl( r, g, b )
|
19
|
-
rgb = ChunkyPNG::Color.rgb( r, g, b )
|
20
|
-
hsl = ChunkyPNG::Color.to_hsl( rgb )
|
21
|
-
hsl
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.from_hsl( h, s, l )
|
25
|
-
ChunkyPNG::Color.from_hsl( h, s, l )
|
26
|
-
end
|
27
|
-
end # class Color
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
5
|
class Image < Pixelart::Image
|
33
6
|
|
34
7
|
|
@@ -81,17 +54,17 @@ def initialize( design: 0,
|
|
81
54
|
end
|
82
55
|
|
83
56
|
## note: first color (index 0) is always nil (default/white or transparent)
|
84
|
-
colors = [ nil ] +
|
57
|
+
colors = [ nil ] + colors.map { |color| Pixelart::Color.parse( color ) }
|
85
58
|
|
86
59
|
## puts " colors:"
|
87
60
|
## pp colors
|
88
61
|
|
89
62
|
img = ChunkyPNG::Image.new( design.width,
|
90
|
-
|
91
|
-
|
63
|
+
design.height,
|
64
|
+
ChunkyPNG::Color::TRANSPARENT ) # why? why not?
|
92
65
|
|
93
|
-
design.each_with_index do |row,
|
94
|
-
row.each_with_index do |color,
|
66
|
+
design.each_with_index do |row, y|
|
67
|
+
row.each_with_index do |color, x|
|
95
68
|
if color > 0
|
96
69
|
pixel = colors[ color ]
|
97
70
|
img[x,y] = pixel
|
@@ -151,110 +124,6 @@ def self.derive_palette( r: nil, g: nil, b: nil,
|
|
151
124
|
end
|
152
125
|
|
153
126
|
|
154
|
-
######
|
155
|
-
# helpers
|
156
|
-
def parse_colors( colors )
|
157
|
-
## convert into ChunkyPNG::Color
|
158
|
-
colors.map { |color| parse_color( color ) }
|
159
|
-
end
|
160
|
-
|
161
|
-
def parse_color( color )
|
162
|
-
if color.is_a?( Integer ) ## e.g. Assumess ChunkyPNG::Color.rgb() or such
|
163
|
-
color ## pass through as is 1:1
|
164
|
-
elsif color.is_a?(String)
|
165
|
-
## note: return an Integer !!! (not a Color class or such!!! )
|
166
|
-
ChunkyPNG::Color.from_hex( color )
|
167
|
-
else
|
168
|
-
raise ArgumentError, "unknown color format; cannot parse - expected rgb hex string e.g. d3d3d3"
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
class Bar ## (nested) class inside Image (e.g. Image::Bar)
|
178
|
-
## make a color bar
|
179
|
-
def initialize( colors:, zoom: 24 )
|
180
|
-
@bar = ChunkyPNG::Image.new( colors.size*zoom,
|
181
|
-
zoom,
|
182
|
-
ChunkyPNG::Color::WHITE ) # why? why not?
|
183
|
-
|
184
|
-
colors.each_with_index do |color,i|
|
185
|
-
zoom.times do |x|
|
186
|
-
zoom.times do |y|
|
187
|
-
@bar[x+zoom*i,y] = color
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|
191
|
-
end # def initialize
|
192
|
-
|
193
|
-
#####
|
194
|
-
# (image) delegates
|
195
|
-
## todo/check: add some more??
|
196
|
-
def save( path, constraints = {} )
|
197
|
-
@bar.save( path, constraints )
|
198
|
-
end
|
199
|
-
|
200
|
-
def width() @bar.width; end
|
201
|
-
def height() @bar.height; end
|
202
|
-
|
203
|
-
## return image ref - use a different name - why? why not?
|
204
|
-
def image() @bar; end
|
205
|
-
end # (nested) class Bar
|
206
127
|
end # class Image
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
class Design
|
211
|
-
def self.find( num ) ## pass in design index number (0 to 127)
|
212
|
-
## todo: add cache (memoize) - why? why not?
|
213
|
-
str = DESIGNS[ num ]
|
214
|
-
design = parse( str )
|
215
|
-
|
216
|
-
puts " design ##{num} (#{design.width}x#{design.height})"
|
217
|
-
## pp design.data
|
218
|
-
## puts
|
219
|
-
|
220
|
-
design
|
221
|
-
end
|
222
|
-
|
223
|
-
|
224
|
-
def self.parse( str )
|
225
|
-
data = str.split('.')
|
226
|
-
new( data )
|
227
|
-
end
|
228
|
-
|
229
|
-
def initialize( data )
|
230
|
-
## todo: add cache (memoize) - why? why not?
|
231
|
-
|
232
|
-
## note: map colors encoded as a string to an array of integers - why? why not?
|
233
|
-
## e.g. "00011111133344411"
|
234
|
-
## =>
|
235
|
-
## [0,0,0,1,1,1,1,1,1,3,3,3,4,4,4,1,1]
|
236
|
-
|
237
|
-
@data = data.map do |row|
|
238
|
-
row.chars.map do |color|
|
239
|
-
color.to_i
|
240
|
-
end
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
## note: design data stored mirrored (data.size is the width NOT height)
|
245
|
-
def width() @data.size; end
|
246
|
-
def height() @data[0].size; end
|
247
|
-
|
248
|
-
def data() @data; end
|
249
|
-
|
250
|
-
def each_with_index( &blk )
|
251
|
-
## note: y,x is reversed - keep for now
|
252
|
-
## (todo/fix later? and "pivot" raw data on init - why? why not?)
|
253
|
-
@data.each_with_index do |row, x|
|
254
|
-
blk.call( row, x )
|
255
|
-
end
|
256
|
-
end
|
257
|
-
end # class Design
|
258
|
-
|
259
128
|
end # module Mooncats
|
260
129
|
|
data/lib/mooncats/structs.rb
CHANGED
@@ -11,20 +11,37 @@ POSES = [
|
|
11
11
|
'Stalking', ## 11
|
12
12
|
]
|
13
13
|
|
14
|
-
|
14
|
+
|
15
|
+
OLD_FACES = [ ## old names for face (expressions)
|
15
16
|
'Smile', ## 00
|
16
17
|
'Frown (Look Down)', ## 01
|
17
18
|
'Frown (Look Up)', ## 10
|
18
19
|
'Flat Whiskers', ## 11
|
19
20
|
]
|
20
21
|
|
21
|
-
|
22
|
+
FACES = [ ## face expressions
|
23
|
+
'Smiling', ## 00
|
24
|
+
'Grumpy', ## 01
|
25
|
+
'Pouting', ## 10
|
26
|
+
'Shy', ## 11
|
27
|
+
]
|
28
|
+
|
29
|
+
|
30
|
+
OLD_FURS = [ ## old names for fur (patterns)
|
22
31
|
'Solid', ## 00
|
23
32
|
'Striped', ## 01
|
24
33
|
'Eyepatch', ## 10
|
25
34
|
'Half/Half', ## 11
|
26
35
|
]
|
27
36
|
|
37
|
+
FURS = [ ## fur (patterns)
|
38
|
+
'Pure', ## 00
|
39
|
+
'Tabby', ## 01
|
40
|
+
'Spotted', ## 10
|
41
|
+
'Tortie', ## 11
|
42
|
+
]
|
43
|
+
|
44
|
+
|
28
45
|
FACINGS = [
|
29
46
|
'Left', # 0
|
30
47
|
'Right', # 1
|
@@ -50,12 +67,15 @@ class Metadata
|
|
50
67
|
def facing
|
51
68
|
@facing ||= FACINGS[ bits[1,1].to_i(2) ] ## use desgin > 63 instead - why? why not?
|
52
69
|
end
|
53
|
-
def face
|
70
|
+
def face ## face (expression)
|
54
71
|
@face ||= FACES[ bits[2,2].to_i(2) ]
|
55
72
|
end
|
56
|
-
|
73
|
+
alias_method :expression, :face
|
74
|
+
|
75
|
+
def fur ## fur (pattern) - add pattern alias - why? why not?
|
57
76
|
@fur ||= FURS[ bits[4,2].to_i(2) ]
|
58
77
|
end
|
78
|
+
|
59
79
|
def pose
|
60
80
|
@poses ||= POSES[ bits[6,2].to_i(2) ] ## use design % 4 instead - why? why not?
|
61
81
|
end
|
@@ -87,7 +107,10 @@ class Metadata
|
|
87
107
|
def rgb() [r,g,b]; end ## add rgb shortcut helper - why? why not?
|
88
108
|
|
89
109
|
def invert?() k >= 128; end
|
90
|
-
|
110
|
+
alias_method :pale?, :invert?
|
111
|
+
|
112
|
+
|
113
|
+
def pattern() k % 64; end ## treat facing left|right as the same - note: conflicts with fur (pattern) - find a better/different name?
|
91
114
|
|
92
115
|
|
93
116
|
def hue
|
@@ -155,6 +178,7 @@ class Metadata
|
|
155
178
|
|
156
179
|
def facing() design.facing; end
|
157
180
|
def face() design.face; end
|
181
|
+
alias_method :expression, :face
|
158
182
|
def fur() design.fur; end
|
159
183
|
def pose() design.pose; end
|
160
184
|
|
@@ -170,23 +194,25 @@ class Metadata
|
|
170
194
|
# enable array-like access to - why? why not?
|
171
195
|
def []( key )
|
172
196
|
case key.to_sym
|
173
|
-
when :id
|
174
|
-
when :genesis
|
175
|
-
when :k
|
176
|
-
when :r
|
177
|
-
when :g
|
178
|
-
when :b
|
179
|
-
when :rgb
|
180
|
-
when :invert
|
181
|
-
|
182
|
-
when :
|
183
|
-
when :
|
184
|
-
when :
|
185
|
-
when :
|
186
|
-
when :
|
187
|
-
when :
|
188
|
-
|
189
|
-
when :
|
197
|
+
when :id then id
|
198
|
+
when :genesis then genesis?
|
199
|
+
when :k then k
|
200
|
+
when :r then r
|
201
|
+
when :g then g
|
202
|
+
when :b then b
|
203
|
+
when :rgb then rgb
|
204
|
+
when :invert,
|
205
|
+
:pale then invert?
|
206
|
+
when :hue then hue
|
207
|
+
when :color then color
|
208
|
+
when :design then design.to_i
|
209
|
+
when :pattern then pattern
|
210
|
+
when :facing then facing
|
211
|
+
when :face,
|
212
|
+
:expression then face
|
213
|
+
when :fur then fur
|
214
|
+
when :pose then pose
|
215
|
+
when :year then year # note: from more via timestamp
|
190
216
|
else
|
191
217
|
@more[ key ]
|
192
218
|
end
|
data/lib/mooncats/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mooncats
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.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-
|
11
|
+
date: 2021-04-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pixelart
|
@@ -92,6 +92,7 @@ files:
|
|
92
92
|
- lib/mooncats.rb
|
93
93
|
- lib/mooncats/composite.rb
|
94
94
|
- lib/mooncats/dataset.rb
|
95
|
+
- lib/mooncats/design.rb
|
95
96
|
- lib/mooncats/designs.rb
|
96
97
|
- lib/mooncats/image.rb
|
97
98
|
- lib/mooncats/structs.rb
|