mooncats 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Manifest.txt +3 -0
- data/lib/mooncats.rb +3 -1
- data/lib/mooncats/composite.rb +69 -0
- data/lib/mooncats/dataset.rb +45 -0
- data/lib/mooncats/image.rb +22 -32
- data/lib/mooncats/structs.rb +151 -0
- data/lib/mooncats/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a440b059c12270381d0f9b58b277a3f06b7e44d1cc1cdc503965ac2f888a2cb9
|
4
|
+
data.tar.gz: e153163695f9e23a07d105f9eccba2d7c666bed7b234f18dead8ca0c1a659ae7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 936a405f9b9abf5cb4118be4c6a3b0d9f49925099a20e56667925b2275c2bcb6a5498055e3c3be2e0c3781297eacb8b616da681a856c061fd553ec533b82344f
|
7
|
+
data.tar.gz: 602fe2482ca77d1004368a809080239b66a01456f529d4b4aa30138eed2ca2f852dd2ab57dc38acaf6c3595f493b05156ffaf4b51b29b1821ad5232ae9f291cf
|
data/Manifest.txt
CHANGED
data/lib/mooncats.rb
CHANGED
@@ -12,8 +12,10 @@ require 'optparse'
|
|
12
12
|
## our own code
|
13
13
|
require 'mooncats/version' # note: let version always go first
|
14
14
|
require 'mooncats/designs'
|
15
|
+
require 'mooncats/structs'
|
15
16
|
require 'mooncats/image'
|
16
|
-
|
17
|
+
require 'mooncats/composite'
|
18
|
+
require 'mooncats/dataset'
|
17
19
|
|
18
20
|
|
19
21
|
|
@@ -0,0 +1,69 @@
|
|
1
|
+
|
2
|
+
module Mooncats
|
3
|
+
class Image
|
4
|
+
class Composite ## nest Composite inside Image - why? why not?
|
5
|
+
|
6
|
+
|
7
|
+
CANVAS_WIDTH = 24 ## sorry - for now "hard-coded" / fixed - 24x24
|
8
|
+
CANVAS_HEIGHT = 24
|
9
|
+
|
10
|
+
def initialize( cols=100, rows=255 )
|
11
|
+
@composite = ChunkyPNG::Image.new( cols*CANVAS_WIDTH,
|
12
|
+
rows*CANVAS_HEIGHT,
|
13
|
+
ChunkyPNG::Color::WHITE ) # why? why not? - use TRANSPARENT (is default?)
|
14
|
+
|
15
|
+
## todo/check - find a better name for cols/rows - why? why not?
|
16
|
+
@cols = cols
|
17
|
+
@rows = rows
|
18
|
+
|
19
|
+
@i = 0 # (track) current index (of added images)
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def add( image )
|
24
|
+
y, x = @i.divmod( @cols )
|
25
|
+
|
26
|
+
puts " width: #{image.width}, height: #{image.height}"
|
27
|
+
|
28
|
+
## try to center image (identicon) in 24x24 canvas
|
29
|
+
## the 4 formats are
|
30
|
+
## - 21×17 - Standing
|
31
|
+
## - 20×14 - Sleeping
|
32
|
+
## - 17×22 - Pouncing
|
33
|
+
## - 20×21 - Stalking
|
34
|
+
## e.g. add left padding (x_center) and
|
35
|
+
## top padding (y_center)
|
36
|
+
x_center, y_center = case [image.width, image.height]
|
37
|
+
when [21,17] then [1,3]
|
38
|
+
when [20,14] then [2,5]
|
39
|
+
when [17,22] then [3,1]
|
40
|
+
when [20,21] then [2,1]
|
41
|
+
## todo/fix: report unknown image format/size!!!!
|
42
|
+
end
|
43
|
+
|
44
|
+
## note: image.image - "unwrap" the "raw" ChunkyPNG::Image
|
45
|
+
@composite.compose!( image.image, x*CANVAS_WIDTH+x_center, y*CANVAS_HEIGHT+y_center )
|
46
|
+
@i += 1
|
47
|
+
end
|
48
|
+
|
49
|
+
alias_method :<<, :add
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
#####
|
54
|
+
# (image) delegates
|
55
|
+
## todo/check: add some more??
|
56
|
+
def save( path, constraints = {} )
|
57
|
+
@composite.save( path, constraints )
|
58
|
+
end
|
59
|
+
|
60
|
+
def width() @composite.width; end
|
61
|
+
def height() @composite.height; end
|
62
|
+
|
63
|
+
## return image ref - use a different name - why? why not?
|
64
|
+
def image() @composite; end
|
65
|
+
|
66
|
+
|
67
|
+
end # class Composite
|
68
|
+
end # class Image
|
69
|
+
end # module Mooncats
|
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Mooncats
|
4
|
+
module Dataset
|
5
|
+
|
6
|
+
def self.read( path='./datasets/mooncats/*.csv' )
|
7
|
+
|
8
|
+
datasets = Dir.glob( path )
|
9
|
+
## pp datasets
|
10
|
+
#=> ["./datasets/mooncats/00.csv",
|
11
|
+
# "./datasets/mooncats/01.csv",
|
12
|
+
# "./datasets/mooncats/02.csv",
|
13
|
+
# "./datasets/mooncats/03.csv",
|
14
|
+
# "./datasets/mooncats/04.csv",
|
15
|
+
# ...]
|
16
|
+
|
17
|
+
rows = []
|
18
|
+
datasets.each do |dataset|
|
19
|
+
rows += CsvHash.read( dataset )
|
20
|
+
end
|
21
|
+
|
22
|
+
## puts " #{rows.size} rows(s)"
|
23
|
+
#=> 25440 rows(s)
|
24
|
+
|
25
|
+
|
26
|
+
### wrap in mooncat struct for easier access
|
27
|
+
mooncats = []
|
28
|
+
rows.each_with_index do |row,i|
|
29
|
+
## print "." if i % 100
|
30
|
+
id = row['id']
|
31
|
+
## note: skip all derived column from id e.g.
|
32
|
+
## - r,g,b, etc.
|
33
|
+
|
34
|
+
mint = row['mint'].to_i
|
35
|
+
|
36
|
+
mooncats << Metadata.new( id )
|
37
|
+
end
|
38
|
+
## print "\n" ## add progress
|
39
|
+
|
40
|
+
mooncats
|
41
|
+
end
|
42
|
+
end # module Dataset
|
43
|
+
end # module Mooncat
|
44
|
+
|
45
|
+
|
data/lib/mooncats/image.rb
CHANGED
@@ -7,27 +7,22 @@ COLORS_GENESIS_WHITE = ['#555555', '#d3d3d3', '#ffffff', '#aaaaaa', '#ff9999']
|
|
7
7
|
COLORS_GENESIS_BLACK = ['#555555', '#222222', '#111111', '#bbbbbb', '#ff9999']
|
8
8
|
|
9
9
|
|
10
|
-
def self.generate(
|
11
|
-
|
10
|
+
def self.generate( id, zoom: 1 )
|
11
|
+
meta = Metadata.new( id )
|
12
12
|
|
13
|
-
|
14
|
-
k = bytes[1]
|
15
|
-
r = bytes[2]
|
16
|
-
g = bytes[3]
|
17
|
-
b = bytes[4]
|
13
|
+
design = meta.design.to_i # note: meta.design is a struct/object - keep/use a local int !!!
|
18
14
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
colors = if genesis
|
23
|
-
if design % 2 === 0 && invert ||
|
24
|
-
design % 2 === 1 && !invert
|
15
|
+
colors = if meta.genesis?
|
16
|
+
if design % 2 == 0 && meta.invert? ||
|
17
|
+
design % 2 == 1 && !meta.invert?
|
25
18
|
COLORS_GENESIS_WHITE
|
26
19
|
else
|
27
20
|
COLORS_GENESIS_BLACK
|
28
21
|
end
|
29
22
|
else
|
30
|
-
derive_palette( r,
|
23
|
+
derive_palette( meta.r,
|
24
|
+
meta.g,
|
25
|
+
meta.b, invert: meta.invert? )
|
31
26
|
end
|
32
27
|
|
33
28
|
new( design: design,
|
@@ -35,6 +30,13 @@ def self.generate( cat_id, zoom: 1 )
|
|
35
30
|
zoom: zoom )
|
36
31
|
end
|
37
32
|
|
33
|
+
### add more (convenience) aliases
|
34
|
+
class << self
|
35
|
+
alias_method :mint, :generate
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
|
38
40
|
|
39
41
|
def initialize( design: 0,
|
40
42
|
colors: COLORS_GENESIS_WHITE,
|
@@ -80,31 +82,19 @@ end
|
|
80
82
|
#####
|
81
83
|
# (image) delegates
|
82
84
|
## todo/check: add some more??
|
83
|
-
def save( path
|
85
|
+
def save( path, constraints = {} )
|
86
|
+
@cat.save( path, constraints )
|
87
|
+
end
|
88
|
+
|
84
89
|
def width() @cat.width; end
|
85
90
|
def height() @cat.height; end
|
86
91
|
|
92
|
+
## return image ref - use a different name - why? why not?
|
93
|
+
def image() @cat; end
|
87
94
|
|
88
95
|
|
89
96
|
##################
|
90
97
|
# (static) helpers
|
91
|
-
def self.hex_to_bytes( str_or_num )
|
92
|
-
if str_or_num.is_a?( Integer ) ## allow passing in of integer to e.g. 0x... etc.
|
93
|
-
num = str_or_num
|
94
|
-
str = '%010x' % num # 5 bytes (10 hex digits/chars)
|
95
|
-
else ## assume string
|
96
|
-
## cut-off optionial 0x
|
97
|
-
str = str_or_num
|
98
|
-
str = str.downcase
|
99
|
-
str = str[2..-1] if str.start_with?( '0x')
|
100
|
-
end
|
101
|
-
|
102
|
-
raise ArgumentError, "expected 5 byte hex string (10 digits/chars); got #{str_or_num}" if str.size != 10
|
103
|
-
|
104
|
-
bytes = [str].pack('H*').bytes
|
105
|
-
bytes
|
106
|
-
end
|
107
|
-
|
108
98
|
def self.derive_palette( r, g, b, invert: false )
|
109
99
|
## note: Color.rgb returns an Integer (e.g. 34113279 - true color or just hex rgba or?)
|
110
100
|
rgb = ChunkyPNG::Color.rgb( r, g, b )
|
@@ -0,0 +1,151 @@
|
|
1
|
+
|
2
|
+
module Mooncats
|
3
|
+
|
4
|
+
### wrap metadata (e.g. pose, fur, facing, color, etc.)
|
5
|
+
## in structs for easy/easier access)
|
6
|
+
|
7
|
+
POSES = [
|
8
|
+
'Standing', ## 00
|
9
|
+
'Sleeping', ## 01
|
10
|
+
'Pouncing', ## 10
|
11
|
+
'Stalking', ## 11
|
12
|
+
]
|
13
|
+
|
14
|
+
FACES = [
|
15
|
+
'Smile', ## 00
|
16
|
+
'Frown (Look Down)', ## 01
|
17
|
+
'Frown (Look Up)', ## 10
|
18
|
+
'Flat Whiskers', ## 11
|
19
|
+
]
|
20
|
+
|
21
|
+
FURS = [
|
22
|
+
'Solid', ## 00
|
23
|
+
'Striped', ## 01
|
24
|
+
'Eyepatch', ## 10
|
25
|
+
'Half/Half', ## 11
|
26
|
+
]
|
27
|
+
|
28
|
+
FACINGS = [
|
29
|
+
'Left', # 0
|
30
|
+
'Right', # 1
|
31
|
+
]
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
class Metadata
|
36
|
+
|
37
|
+
class Design ## nested classed - why? lets you use Metadata::Design "standalone", that is, without 5-byte id
|
38
|
+
def initialize( num ) # 0-127 design num(ber)
|
39
|
+
@num = num
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_i() @num; end
|
43
|
+
|
44
|
+
def bits ## keep private / internal - why? why not?
|
45
|
+
## keep 128 possible designs 0 to 127
|
46
|
+
## as 7 bit string e.g. 01010111 for now - why? why not?
|
47
|
+
@bits ||= '%08b' % @num
|
48
|
+
end
|
49
|
+
|
50
|
+
def facing
|
51
|
+
@facing ||= FACINGS[ bits[1,1].to_i(2) ] ## use desgin > 63 instead - why? why not?
|
52
|
+
end
|
53
|
+
def face
|
54
|
+
@face ||= FACES[ bits[2,2].to_i(2) ]
|
55
|
+
end
|
56
|
+
def fur
|
57
|
+
@fur ||= FURS[ bits[4,2].to_i(2) ]
|
58
|
+
end
|
59
|
+
def pose
|
60
|
+
@poses ||= POSES[ bits[6,2].to_i(2) ] ## use design % 4 instead - why? why not?
|
61
|
+
end
|
62
|
+
end ## (nested) class Metadata::Design
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
def initialize( id, **more )
|
68
|
+
@bytes = self.class.hex_to_bytes( id )
|
69
|
+
|
70
|
+
## add support for more "external" meta data
|
71
|
+
## ## e.g. mint, mint_block, etc.
|
72
|
+
@more = more
|
73
|
+
end
|
74
|
+
|
75
|
+
def id
|
76
|
+
@id ||= @bytes.map { |byte| '%02x' % byte }.join
|
77
|
+
end
|
78
|
+
|
79
|
+
def genesis?
|
80
|
+
@bytes[0] != 0 ## note: convert to bool (if zero assume NOT genesis)
|
81
|
+
end
|
82
|
+
def k() @bytes[1]; end
|
83
|
+
def r() @bytes[2]; end
|
84
|
+
def g() @bytes[3]; end
|
85
|
+
def b() @bytes[4]; end
|
86
|
+
|
87
|
+
def rgb() [r,g,b]; end ## add rgb shortcut helper - why? why not?
|
88
|
+
|
89
|
+
def invert?() k >= 128; end
|
90
|
+
def pattern() k % 64; end ## treat facing left|right as the same
|
91
|
+
|
92
|
+
|
93
|
+
def design
|
94
|
+
@design ||= Design.new( k % 128 )
|
95
|
+
end
|
96
|
+
|
97
|
+
def facing() design.facing; end
|
98
|
+
def face() design.face; end
|
99
|
+
def fur() design.fur; end
|
100
|
+
def pose() design.pose; end
|
101
|
+
|
102
|
+
|
103
|
+
####
|
104
|
+
# more "external" attributes
|
105
|
+
def mint() @more[:mint]; end
|
106
|
+
|
107
|
+
#####
|
108
|
+
# enable array-like access to - why? why not?
|
109
|
+
def []( key )
|
110
|
+
case key.to_sym
|
111
|
+
when :id then id
|
112
|
+
when :genesis then genesis?
|
113
|
+
when :k then k
|
114
|
+
when :r then r
|
115
|
+
when :g then g
|
116
|
+
when :b then b
|
117
|
+
when :rgb then rgb
|
118
|
+
when :invert then invert?
|
119
|
+
when :design then design.to_i
|
120
|
+
when :pattern then pattern
|
121
|
+
when :facing then facing
|
122
|
+
when :face then face
|
123
|
+
when :fur then fur
|
124
|
+
when :pose then pose
|
125
|
+
else
|
126
|
+
@more[ key ]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
##################
|
132
|
+
# (static) helpers
|
133
|
+
def self.hex_to_bytes( str_or_num )
|
134
|
+
if str_or_num.is_a?( Integer ) ## allow passing in of integer to e.g. 0x... etc.
|
135
|
+
num = str_or_num
|
136
|
+
str = '%010x' % num # 5 bytes (10 hex digits/chars)
|
137
|
+
else ## assume string
|
138
|
+
## cut-off optionial 0x
|
139
|
+
str = str_or_num
|
140
|
+
str = str.downcase
|
141
|
+
str = str[2..-1] if str.start_with?( '0x')
|
142
|
+
end
|
143
|
+
|
144
|
+
raise ArgumentError, "expected 5 byte hex string (10 digits/chars); got #{str_or_num}" if str.size != 10
|
145
|
+
|
146
|
+
bytes = [str].pack('H*').bytes
|
147
|
+
bytes
|
148
|
+
end
|
149
|
+
end # class Metadata
|
150
|
+
|
151
|
+
end # module Mooncats
|
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: 0.1.
|
4
|
+
version: 0.1.2
|
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-03-
|
11
|
+
date: 2021-03-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chunky_png
|
@@ -92,8 +92,11 @@ files:
|
|
92
92
|
- Rakefile
|
93
93
|
- bin/mooncat
|
94
94
|
- lib/mooncats.rb
|
95
|
+
- lib/mooncats/composite.rb
|
96
|
+
- lib/mooncats/dataset.rb
|
95
97
|
- lib/mooncats/designs.rb
|
96
98
|
- lib/mooncats/image.rb
|
99
|
+
- lib/mooncats/structs.rb
|
97
100
|
- lib/mooncats/version.rb
|
98
101
|
homepage: https://github.com/cryptocopycats/mooncats
|
99
102
|
licenses:
|