mooncats 1.0.1 → 1.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 +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
|