mooncats 0.1.0 → 0.1.2
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 +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:
|