artbase 0.1.0 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,329 @@
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 1000 then [25, 40]
55
+ when 2200 then [50, 44]
56
+ when 2222 then [50, 45]
57
+ when 2469 then [50, 50]
58
+ when 3000 then [100, 30] ## or use 50*60 - why? why not?
59
+ when 3500 then [100, 35] ## or use 50*x ??
60
+ when 3979 then [100, 40]
61
+ when 4000 then [100, 40] ## or use 50x80 - why? why not?
62
+ when 4444 then [100, 45] ## or use 50x??
63
+ when 5000 then [100, 50] ## or use 50x100 - why? why not?
64
+ when 5555 then [100, 56] # 5600 (45 left empty)
65
+ when 6666 then [100, 67] # 6700 (34 left empty)
66
+ when 6688 then [100, 67] # 6700 (12 left empty)
67
+ when 6969 then [100, 70] # 7000 (31 left empty)
68
+ when 7500 then [100, 75]
69
+ when 8888 then [100, 89]
70
+ when 9969 then [100,100]
71
+ when 10000 then [100,100]
72
+ else
73
+ raise ArgumentError, "sorry - unknown composite count #{composite_count}/#{@count} for now"
74
+ end
75
+
76
+ composite = ImageComposite.new( cols, rows,
77
+ width: @width,
78
+ height: @height )
79
+
80
+
81
+ count = 0
82
+ each_image do |img, id|
83
+ puts "==> #{id}"
84
+ composite << if mirror
85
+ img.mirror
86
+ else
87
+ img
88
+ end
89
+
90
+ count += 1
91
+ break if limit && count >= limit
92
+ end
93
+
94
+
95
+ slug = "#{@slug}"
96
+ slug += "#{limit}" if limit
97
+ slug += "_left" if mirror
98
+
99
+ path = "./#{@slug}/tmp/#{slug}-#{@width}x#{@height}.png"
100
+ puts " saving #{path}..."
101
+ composite.save( path )
102
+
103
+ if composite_count < 1000
104
+ path = "./#{@slug}/tmp/#{slug}-#{@width}x#{@height}@2x.png"
105
+ puts " saving 2x #{path}..."
106
+ composite.zoom(2).save( path )
107
+ end
108
+ end
109
+
110
+
111
+
112
+
113
+ def calc_attribute_counters ## todo/check: use a different name _counts/_stats etc - why? why not?
114
+
115
+ attributes_by_count = { count: 0,
116
+ by_count: Hash.new(0)
117
+ }
118
+ counter = {}
119
+
120
+
121
+ each_meta do |meta, id| ## todo/fix: change id to index
122
+ traits = meta.traits
123
+ # print "#{traits.size} - "
124
+ # pp traits
125
+
126
+ print "#{id}.." if id % 100 == 0 ## print progress report
127
+
128
+ attributes_by_count[ :count ] +=1
129
+ attributes_by_count[ :by_count ][ traits.size ] += 1
130
+
131
+ traits.each do |trait_type, trait_value|
132
+ trait_type = _normalize_trait_type( trait_type )
133
+ trait_value = _normalize_trait_value( trait_value )
134
+
135
+
136
+ rec = counter[ trait_type ] ||= { count: 0,
137
+ by_type: Hash.new(0)
138
+ }
139
+ rec[ :count ] +=1
140
+ rec[ :by_type ][ trait_value ] += 1
141
+ end
142
+ end
143
+
144
+ print "\n"
145
+ puts
146
+
147
+ ## return all-in-one hash
148
+ {
149
+ total: attributes_by_count,
150
+ traits: counter,
151
+ }
152
+ end
153
+
154
+
155
+ def dump_attributes
156
+ stats = calc_attribute_counters
157
+
158
+ total = stats[:total]
159
+ counter = stats[:traits]
160
+
161
+ puts
162
+ puts "attribute usage / counts:"
163
+ pp total
164
+ puts
165
+
166
+ puts "#{counter.size} attribute(s):"
167
+ counter.each do |trait_name, trait_rec|
168
+ puts " #{trait_name} #{trait_rec[:count]} (#{trait_rec[:by_type].size} uniques)"
169
+ end
170
+
171
+ puts
172
+ pp counter
173
+ end
174
+
175
+
176
+
177
+
178
+ ## order - allow "custom" attribute order export
179
+ ## renames - allow renames of attributes
180
+ def export_attributes(
181
+ order: [],
182
+ renames: {}
183
+ )
184
+
185
+ ## step 1: get counters
186
+ stats = calc_attribute_counters
187
+
188
+ total = stats[:total]
189
+ counter = stats[:traits]
190
+
191
+ puts
192
+ puts "attribute usage / counts:"
193
+ pp total
194
+ puts
195
+
196
+ puts "#{counter.size} attribute(s):"
197
+ counter.each do |trait_name, trait_rec|
198
+ puts " #{trait_name} #{trait_rec[:count]} (#{trait_rec[:by_type].size} uniques)"
199
+ end
200
+
201
+
202
+ trait_names = []
203
+ trait_names += order ## get attributes if any in pre-defined order
204
+ counter.each do |trait_name, _|
205
+ if trait_names.include?( trait_name )
206
+ next ## skip already included
207
+ else
208
+ trait_names << trait_name
209
+ end
210
+ end
211
+
212
+
213
+ recs = []
214
+
215
+
216
+ ## step 2: get tabular data
217
+ each_meta do |meta, id| ## todo/fix: change id to index
218
+
219
+ traits = meta.traits
220
+ # print "#{traits.size} - "
221
+ # pp traits
222
+
223
+ print "#{id}.." if id % 100 == 0 ## print progress report
224
+
225
+ ## setup empty hash table (with all attributes)
226
+ rec = {}
227
+
228
+ ## note: use __Slug__& __Name__
229
+ ## to avoid conflict with attribute names
230
+ ## e.g. attribute with "Name" will overwrite built-in and so on
231
+
232
+ rec['__Slug__'] = if respond_to?( :_meta_slugify )
233
+ _meta_slugify( meta, id )
234
+ else
235
+ ## default to id (six digits) as string with leading zeros
236
+ ## for easy sorting using strings
237
+ ## e.g. 1 => '000001'
238
+ ## 2 => '000002'
239
+ '%06d' % id
240
+ end
241
+
242
+ rec['__Name__'] = meta.name
243
+
244
+ ## add all attributes/traits names/keys
245
+ trait_names.reduce( rec ) { |h,value| h[value] = []; h }
246
+ ## pp rec
247
+
248
+ ## note: use an array (to allow multiple values for attributes)
249
+ traits.each do |trait_type, trait_value|
250
+ trait_type = _normalize_trait_type( trait_type )
251
+ trait_value = _normalize_trait_value( trait_value )
252
+
253
+ values = rec[ trait_type ]
254
+ values << trait_value
255
+ end
256
+ recs << rec
257
+ end
258
+ print "\n"
259
+
260
+ ## pp recs
261
+
262
+ ## flatten recs
263
+ data = []
264
+ recs.each do |rec|
265
+ row = rec.values.map do |value|
266
+ if value.is_a?( Array )
267
+ value.join( ' / ' )
268
+ else
269
+ value
270
+ end
271
+ end
272
+ data << row
273
+ end
274
+
275
+
276
+ ## sort by slug
277
+ data = data.sort {|l,r| l[0] <=> r[0] }
278
+ pp data
279
+
280
+ ### save dataset
281
+ ## note: change first colum Slug to ID - only used for "internal" sort etc.
282
+ headers = ['ID', 'Name']
283
+ headers += trait_names.map do |trait_name| ## check for renames
284
+ renames[trait_name] || trait_name
285
+ end
286
+
287
+
288
+ path = "./#{@slug}/tmp/#{@slug}.csv"
289
+ dirname = File.dirname( path )
290
+ FileUtils.mkdir_p( dirname ) unless Dir.exist?( dirname )
291
+
292
+ File.open( path, 'w:utf-8' ) do |f|
293
+ f.write( headers.join( ', ' ))
294
+ f.write( "\n" )
295
+ ## note: replace ID with our own internal running (zero-based) counter
296
+ data.each_with_index do |row,i|
297
+ f.write( ([i]+row[1..-1]).join( ', '))
298
+ f.write( "\n" )
299
+ end
300
+ end
301
+ end
302
+
303
+
304
+
305
+
306
+ #############
307
+ # "private" helpers
308
+
309
+ def _normalize_trait_type( trait_type )
310
+ if @patch && @patch[:trait_types]
311
+ @patch[:trait_types][ trait_type ] || trait_type
312
+ else
313
+ trait_type
314
+ end
315
+ end
316
+
317
+ def _normalize_trait_value( trait_value )
318
+ if @patch && @patch[:trait_values]
319
+ @patch[:trait_values][ trait_value ] || trait_value
320
+ else
321
+ trait_value
322
+ end
323
+ end
324
+
325
+
326
+
327
+
328
+ end # class Base
329
+ end # module Artbase
@@ -1,39 +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
-
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
+