artbase-cocos 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+