artbase-cocos 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 631db0140f623a59d67e52957f2b9f58020239dc02a3b5ac2aa9e15126a9df85
4
+ data.tar.gz: edbfda7a4d05e2827c7229def1d25e6b0146319bfbcf8cb8e81d77997c83829e
5
+ SHA512:
6
+ metadata.gz: 480f00c1d0b1f303037373787293302997287323b4f2b41b5d7db8741430ad39c98cfec0edd516a842a718bafb0a476e5f93bcf7d48f64af07432025f0bf25e3
7
+ data.tar.gz: 6e1e364752bce64215a32f93b29eda79742698d6dc65c4ca9a7737c359a054bf20073cdd1181eadc6fa09c5c7f5c34f32223722d359b03c10d0c867db9d09164
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ ### 0.0.1 / 2022-11-26
2
+
3
+ * Everything is new. First release
data/Manifest.txt ADDED
@@ -0,0 +1,15 @@
1
+ CHANGELOG.md
2
+ Manifest.txt
3
+ README.md
4
+ Rakefile
5
+ lib/artbase-cocos.rb
6
+ lib/artbase-cocos/attributes.rb
7
+ lib/artbase-cocos/collection/base.rb
8
+ lib/artbase-cocos/collection/image.rb
9
+ lib/artbase-cocos/collection/token.rb
10
+ lib/artbase-cocos/collection/token_meta.rb
11
+ lib/artbase-cocos/helper.rb
12
+ lib/artbase-cocos/image.rb
13
+ lib/artbase-cocos/image/sample.rb
14
+ lib/artbase-cocos/retry.rb
15
+ lib/artbase-cocos/version.rb
data/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # artbase-cocos - artbase (shared) code commons (cocos); read artbase collection configs & metadata; download collection token metadata, images, and more
2
+
3
+
4
+ * home :: [github.com/pixelartexchange/artbase](https://github.com/pixelartexchange/artbase)
5
+ * bugs :: [github.com/pixelartexchange/artbase/issues](https://github.com/pixelartexchange/artbase/issues)
6
+ * gem :: [rubygems.org/gems/artbase-cocos](https://rubygems.org/gems/artbase-cocos)
7
+ * rdoc :: [rubydoc.info/gems/artbase-cocos](http://rubydoc.info/gems/artbase-cocos)
8
+
9
+
10
+
11
+ ## Usage
12
+
13
+ To be done
14
+
15
+
16
+
17
+
18
+
19
+ ## License
20
+
21
+ The `artbase` scripts are dedicated to the public domain.
22
+ Use it as you please with no restrictions whatsoever.
23
+
24
+
25
+ ## Questions? Comments?
26
+
27
+ Post them on the [D.I.Y. Punk (Pixel) Art reddit](https://old.reddit.com/r/DIYPunkArt). Thanks.
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ require 'hoe'
2
+ require './lib/artbase-cocos/version.rb'
3
+
4
+
5
+ ###
6
+ # hack/ quick fix for broken intuit_values - overwrite with dummy
7
+ class Hoe
8
+ def intuit_values( input ); end
9
+ end
10
+
11
+
12
+ Hoe.spec 'artbase-cocos' do
13
+
14
+ self.version = Artbase::Module::Cocos::VERSION
15
+
16
+ self.summary = "artbase-cocos - artbase (shared) code commons (cocos); read artbase collection configs & metadata; download collection token metadata, images, and more"
17
+ self.description = summary
18
+
19
+ self.urls = { home: 'https://github.com/pixelartexchange/artbase'}
20
+
21
+ self.author = 'Gerald Bauer'
22
+ self.email = 'wwwmake@googlegroups.com'
23
+
24
+ # switch extension to .markdown for gihub formatting
25
+ self.readme_file = 'README.md'
26
+ self.history_file = 'CHANGELOG.md'
27
+
28
+ self.extra_deps = [
29
+ ['cocos', '>= 0.1.2'],
30
+ ['pixelart', '>= 1.3.6'],
31
+ ['webclient', '>= 0.2.2'], ## weblclient part of cocos?
32
+ ]
33
+
34
+ self.licenses = ['Public Domain']
35
+
36
+ self.spec_extras = {
37
+ required_ruby_version: '>= 2.2.2'
38
+ }
39
+
40
+ end
@@ -0,0 +1,83 @@
1
+
2
+
3
+ def counter_to_text( counter )
4
+
5
+ counter = counter.to_a
6
+
7
+ attribute_counter = counter[0]
8
+ more_counter = counter[1..-1]
9
+
10
+
11
+ puts "Attribute Counts\n"
12
+ trait_type, h = attribute_counter
13
+
14
+ total = h[:by_type].values.reduce(0) { |sum,count| sum+count }
15
+
16
+
17
+ types = h[:by_type]
18
+ types = types.sort { |l,r| l[0]<=>r[0] } ## sort by name
19
+
20
+ puts "\n"
21
+ puts "|Name|Total (%)|"
22
+ puts "|--------|----------:|"
23
+
24
+ types.each do |rec|
25
+ name = rec[0]
26
+ count = rec[1]
27
+ percent = Float(count*100)/Float(total)
28
+
29
+ puts "| **#{name} Attributes** | #{count} (#{'%.2f' % percent}) |"
30
+ end
31
+ puts "\n"
32
+
33
+ more_counter.each_with_index do |(trait_type, h),i|
34
+ print " · " if i > 0 ## add separator
35
+ print "#{trait_type } (#{h[:by_type].size})"
36
+ end
37
+ puts "\n\n"
38
+
39
+
40
+
41
+ more_counter.each do |trait_type, h|
42
+ print "### #{trait_type } (#{h[:by_type].size}) - "
43
+ print "∑Total #{h[:count]}/#{total}\n"
44
+
45
+ puts "\n"
46
+ puts "|Name|Total (%)|"
47
+ puts "|--------|----------:|"
48
+
49
+ types = h[:by_type]
50
+ types = types.sort do |l,r|
51
+ # sort by 1) by count
52
+ # 2) by name a-z
53
+ res = r[1] <=> l[1]
54
+ res = l[0] <=> r[0] if res == 0
55
+ res
56
+ end ## sort by count
57
+ types.each do |rec|
58
+ name = rec[0]
59
+ count = rec[1]
60
+ percent = Float(count*100)/Float(total)
61
+
62
+ puts "| **#{name}** | #{count} (#{'%.2f' % percent}) |"
63
+ end
64
+ puts "\n\n"
65
+ end
66
+ end
67
+
68
+
69
+
70
+
71
+ def counter_to_csv( counter )
72
+
73
+ puts "type, name, count"
74
+ counter.each do |trait_type, h|
75
+ puts "#{trait_type}, ∑ Total, #{h[:count]}"
76
+ h[:by_type].each do |trait_value, count|
77
+ puts "#{trait_type}, #{trait_value}, #{count}"
78
+ end
79
+ end
80
+ end
81
+
82
+
83
+
@@ -0,0 +1,332 @@
1
+
2
+ module Artbase
3
+ class Base ## "abstract" Base collection - check -use a different name - why? why not?
4
+
5
+
6
+ def convert_images( overwrite: )
7
+ image_dir = "./#{@slug}/token-i"
8
+ Image.convert( image_dir, from: 'jpg', to: 'png', overwrite: overwrite )
9
+ Image.convert( image_dir, from: 'gif', to: 'png', overwrite: overwrite )
10
+ Image.convert( image_dir, from: 'svg', to: 'png', overwrite: overwrite )
11
+ end
12
+
13
+
14
+
15
+ def make_strip
16
+ composite_count = @count - @excludes.size
17
+
18
+ composite = ImageComposite.new( 9, 1,
19
+ width: @width,
20
+ height: @height )
21
+
22
+ i = 0
23
+ each_image do |img, id|
24
+ puts "==> [#{i+1}/9] #{id}"
25
+ composite << img
26
+
27
+ i += 1
28
+ break if i >= 9
29
+ end
30
+
31
+
32
+ composite.save( "./#{@slug}/tmp/#{@slug}-strip.png" )
33
+ end
34
+
35
+
36
+
37
+ def make_composite( limit: nil,
38
+ mirror: false )
39
+ ### use well-known / pre-defined (default) grids
40
+ ## (cols x rows) for now - why? why not?
41
+
42
+ composite_count = if limit
43
+ limit
44
+ else
45
+ @count - @excludes.size
46
+ end
47
+
48
+ cols, rows = case composite_count
49
+ when 99 then [10, 10]
50
+ when 100 then [10, 10]
51
+ when 150 then [15, 10]
52
+ when 314 then [15, 21]
53
+ when 500 then [25, 20]
54
+ when 946 then [25, 38]
55
+ when 1000 then [25, 40]
56
+ when 1300 then [25, 52]
57
+ when 2048 then [50, 41]
58
+ when 2077 then [50, 42]
59
+ when 2200 then [50, 44]
60
+ when 2222 then [50, 45]
61
+ when 2469 then [50, 50]
62
+ when 3000 then [100, 30] ## or use 50*60 - why? why not?
63
+ when 3500 then [100, 35] ## or use 50*x ??
64
+ when 3979 then [100, 40]
65
+ when 4000 then [100, 40] ## or use 50x80 - why? why not?
66
+ when 4444 then [100, 45] ## or use 50x??
67
+ when 5000 then [100, 50] ## or use 50x100 - why? why not?
68
+ when 5555 then [100, 56] # 5600 (45 left empty)
69
+ when 6666 then [100, 67] # 6700 (34 left empty)
70
+ when 6688 then [100, 67] # 6700 (12 left empty)
71
+ when 6969 then [100, 70] # 7000 (31 left empty)
72
+ when 7500 then [100, 75]
73
+ when 8888 then [100, 89]
74
+ when 9969 then [100,100]
75
+ when 10000 then [100,100]
76
+ else
77
+ raise ArgumentError, "sorry - unknown composite count #{composite_count}/#{@count} for now"
78
+ end
79
+
80
+ composite = ImageComposite.new( cols, rows,
81
+ width: @width,
82
+ height: @height )
83
+
84
+
85
+ count = 0
86
+ each_image do |img, id|
87
+ puts "==> #{id}"
88
+ composite << if mirror
89
+ img.mirror
90
+ else
91
+ img
92
+ end
93
+
94
+ count += 1
95
+ break if limit && count >= limit
96
+ end
97
+
98
+
99
+ slug = "#{@slug}"
100
+ slug += "#{limit}" if limit
101
+ slug += "_left" if mirror
102
+
103
+ path = "./#{@slug}/tmp/#{slug}-#{@width}x#{@height}.png"
104
+ puts " saving #{path}..."
105
+ composite.save( path )
106
+
107
+ if composite_count < 1000
108
+ path = "./#{@slug}/tmp/#{slug}-#{@width}x#{@height}@2x.png"
109
+ puts " saving 2x #{path}..."
110
+ composite.zoom(2).save( path )
111
+ end
112
+ end
113
+
114
+
115
+
116
+ def calc_attribute_counters ## todo/check: use a different name _counts/_stats etc - why? why not?
117
+
118
+ attributes_by_count = { count: 0,
119
+ by_count: Hash.new(0)
120
+ }
121
+ counter = {}
122
+
123
+
124
+ each_meta do |meta, id| ## todo/fix: change id to index
125
+ traits = meta.traits
126
+ # print "#{traits.size} - "
127
+ # pp traits
128
+
129
+ print "#{id}.." if id % 100 == 0 ## print progress report
130
+
131
+ attributes_by_count[ :count ] +=1
132
+ attributes_by_count[ :by_count ][ traits.size ] += 1
133
+
134
+ traits.each do |trait_type, trait_value|
135
+ trait_type = _normalize_trait_type( trait_type )
136
+ trait_value = _normalize_trait_value( trait_value )
137
+
138
+
139
+ rec = counter[ trait_type ] ||= { count: 0,
140
+ by_type: Hash.new(0)
141
+ }
142
+ rec[ :count ] +=1
143
+ rec[ :by_type ][ trait_value ] += 1
144
+ end
145
+ end
146
+
147
+ print "\n"
148
+ puts
149
+
150
+ ## return all-in-one hash
151
+ {
152
+ total: attributes_by_count,
153
+ traits: counter,
154
+ }
155
+ end
156
+
157
+
158
+ def dump_attributes
159
+ stats = calc_attribute_counters
160
+
161
+ total = stats[:total]
162
+ counter = stats[:traits]
163
+
164
+ puts
165
+ puts "attribute usage / counts:"
166
+ pp total
167
+ puts
168
+
169
+ puts "#{counter.size} attribute(s):"
170
+ counter.each do |trait_name, trait_rec|
171
+ puts " #{trait_name} #{trait_rec[:count]} (#{trait_rec[:by_type].size} uniques)"
172
+ end
173
+
174
+ puts
175
+ pp counter
176
+ end
177
+
178
+
179
+
180
+
181
+ ## order - allow "custom" attribute order export
182
+ ## renames - allow renames of attributes
183
+ def export_attributes(
184
+ order: [],
185
+ renames: {}
186
+ )
187
+
188
+ ## step 1: get counters
189
+ stats = calc_attribute_counters
190
+
191
+ total = stats[:total]
192
+ counter = stats[:traits]
193
+
194
+ puts
195
+ puts "attribute usage / counts:"
196
+ pp total
197
+ puts
198
+
199
+ puts "#{counter.size} attribute(s):"
200
+ counter.each do |trait_name, trait_rec|
201
+ puts " #{trait_name} #{trait_rec[:count]} (#{trait_rec[:by_type].size} uniques)"
202
+ end
203
+
204
+
205
+ trait_names = []
206
+ trait_names += order ## get attributes if any in pre-defined order
207
+ counter.each do |trait_name, _|
208
+ if trait_names.include?( trait_name )
209
+ next ## skip already included
210
+ else
211
+ trait_names << trait_name
212
+ end
213
+ end
214
+
215
+
216
+ recs = []
217
+
218
+
219
+ ## step 2: get tabular data
220
+ each_meta do |meta, id| ## todo/fix: change id to index
221
+
222
+ traits = meta.traits
223
+ # print "#{traits.size} - "
224
+ # pp traits
225
+
226
+ print "#{id}.." if id % 100 == 0 ## print progress report
227
+
228
+ ## setup empty hash table (with all attributes)
229
+ rec = {}
230
+
231
+ ## note: use __Slug__& __Name__
232
+ ## to avoid conflict with attribute names
233
+ ## e.g. attribute with "Name" will overwrite built-in and so on
234
+
235
+ rec['__Slug__'] = if respond_to?( :_meta_slugify )
236
+ _meta_slugify( meta, id )
237
+ else
238
+ ## default to id (six digits) as string with leading zeros
239
+ ## for easy sorting using strings
240
+ ## e.g. 1 => '000001'
241
+ ## 2 => '000002'
242
+ '%06d' % id
243
+ end
244
+
245
+ rec['__Name__'] = meta.name
246
+
247
+ ## add all attributes/traits names/keys
248
+ trait_names.reduce( rec ) { |h,value| h[value] = []; h }
249
+ ## pp rec
250
+
251
+ ## note: use an array (to allow multiple values for attributes)
252
+ traits.each do |trait_type, trait_value|
253
+ trait_type = _normalize_trait_type( trait_type )
254
+ trait_value = _normalize_trait_value( trait_value )
255
+
256
+ values = rec[ trait_type ]
257
+ values << trait_value
258
+ end
259
+ recs << rec
260
+ end
261
+ print "\n"
262
+
263
+ ## pp recs
264
+
265
+ ## flatten recs
266
+ data = []
267
+ recs.each do |rec|
268
+ row = rec.values.map do |value|
269
+ if value.is_a?( Array )
270
+ value.join( ' / ' )
271
+ else
272
+ value
273
+ end
274
+ end
275
+ data << row
276
+ end
277
+
278
+
279
+ ## sort by slug
280
+ data = data.sort {|l,r| l[0] <=> r[0] }
281
+ pp data
282
+
283
+ ### save dataset
284
+ ## note: change first colum Slug to ID - only used for "internal" sort etc.
285
+ headers = ['ID', 'Name']
286
+ headers += trait_names.map do |trait_name| ## check for renames
287
+ renames[trait_name] || trait_name
288
+ end
289
+
290
+
291
+ path = "./#{@slug}/tmp/#{@slug}.csv"
292
+ dirname = File.dirname( path )
293
+ FileUtils.mkdir_p( dirname ) unless Dir.exist?( dirname )
294
+
295
+ File.open( path, 'w:utf-8' ) do |f|
296
+ f.write( headers.join( ', ' ))
297
+ f.write( "\n" )
298
+ ## note: replace ID with our own internal running (zero-based) counter
299
+ data.each_with_index do |row,i|
300
+ f.write( ([i]+row[1..-1]).join( ', '))
301
+ f.write( "\n" )
302
+ end
303
+ end
304
+ end
305
+
306
+
307
+
308
+
309
+ #############
310
+ # "private" helpers
311
+
312
+ def _normalize_trait_type( trait_type )
313
+ if @patch && @patch[:trait_types]
314
+ @patch[:trait_types][ trait_type ] || trait_type
315
+ else
316
+ trait_type
317
+ end
318
+ end
319
+
320
+ def _normalize_trait_value( trait_value )
321
+ if @patch && @patch[:trait_values]
322
+ @patch[:trait_values][ trait_value ] || trait_value
323
+ else
324
+ trait_value
325
+ end
326
+ end
327
+
328
+
329
+
330
+
331
+ end # class Base
332
+ end # module Artbase
@@ -0,0 +1,39 @@
1
+
2
+
3
+ class ImageCollection
4
+
5
+ attr_reader :slug, :count
6
+
7
+ def initialize( slug, count,
8
+ image_base: ) # check: rename count to items or such - why? why not?
9
+ @slug = slug
10
+ @count = count
11
+ @image_base = image_base
12
+ end
13
+
14
+ def download_images( range=(0...@count) )
15
+ start = Time.now
16
+ delay_in_s = 0.3
17
+
18
+ range.each do |offset|
19
+ image_src = @image_base.sub( '{id}', offset.to_s )
20
+
21
+ puts "==> #{offset} - #{@slug}..."
22
+
23
+ ## note: will auto-add format file extension (e.g. .png, .jpg)
24
+ ## depending on http content type!!!!!
25
+ copy_image( image_src, "./#{@slug}/image-i/#{offset}" )
26
+
27
+ stop = Time.now
28
+ diff = stop - start
29
+
30
+ mins = diff / 60 ## todo - use floor or such?
31
+ secs = diff % 60
32
+ puts "up #{mins} mins #{secs} secs (total #{diff} secs)"
33
+
34
+ puts "sleeping #{delay_in_s}s..."
35
+ sleep( delay_in_s )
36
+ end
37
+ end
38
+ end # class ImageCollection
39
+