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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 73a562781defbd28b7cd681aae41379de40fbf3704a5a97834ce530d71dda15f
4
- data.tar.gz: 8abb18f6713ab38a9e68a84acff16ca3f3e71fb57edc93cb15f204b612c88804
3
+ metadata.gz: a440b059c12270381d0f9b58b277a3f06b7e44d1cc1cdc503965ac2f888a2cb9
4
+ data.tar.gz: e153163695f9e23a07d105f9eccba2d7c666bed7b234f18dead8ca0c1a659ae7
5
5
  SHA512:
6
- metadata.gz: 34f9b2e6117b7a8fe4134dc20cbdb9541cbb97500e278853d76defeca1d48b6fa32d312de84ec557701ccf5835108e4bffbfc1b12bb27f71f031fb6aa6899c13
7
- data.tar.gz: aef96b644a304e287ee44b7539ea2705b7c98c2d9a40cdb4c3ef76ff1b59b96ec380ee3b5ec22d0acf70ed760748fefdfcd554e3eb30ad1cdab79b66362322ec
6
+ metadata.gz: 936a405f9b9abf5cb4118be4c6a3b0d9f49925099a20e56667925b2275c2bcb6a5498055e3c3be2e0c3781297eacb8b616da681a856c061fd553ec533b82344f
7
+ data.tar.gz: 602fe2482ca77d1004368a809080239b66a01456f529d4b4aa30138eed2ca2f852dd2ab57dc38acaf6c3595f493b05156ffaf4b51b29b1821ad5232ae9f291cf
data/Manifest.txt CHANGED
@@ -5,6 +5,9 @@ README.md
5
5
  Rakefile
6
6
  bin/mooncat
7
7
  lib/mooncats.rb
8
+ lib/mooncats/composite.rb
9
+ lib/mooncats/dataset.rb
8
10
  lib/mooncats/designs.rb
9
11
  lib/mooncats/image.rb
12
+ lib/mooncats/structs.rb
10
13
  lib/mooncats/version.rb
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
+
@@ -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( cat_id, zoom: 1 )
11
- bytes = hex_to_bytes( cat_id )
10
+ def self.generate( id, zoom: 1 )
11
+ meta = Metadata.new( id )
12
12
 
13
- genesis = bytes[0] != 0 ## note: convert to bool (if zero assume NOT genesis)
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
- invert = k >= 128
20
- design = k % 128
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, g, b, invert: invert )
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 ) @cat.save( path ); end
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
@@ -3,7 +3,7 @@ module Mooncats
3
3
 
4
4
  MAJOR = 0
5
5
  MINOR = 1
6
- PATCH = 0
6
+ PATCH = 2
7
7
  VERSION = [MAJOR,MINOR,PATCH].join('.')
8
8
 
9
9
  def self.version
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.0
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-16 00:00:00.000000000 Z
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: