artbase 0.1.0 → 0.2.0

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.
@@ -0,0 +1,268 @@
1
+
2
+ module Artbase
3
+ class Base ## "abstract" Base collection - check -use a different name - why? why not?
4
+
5
+
6
+
7
+ def make_composite
8
+ ### use well-known / pre-defined (default) grids
9
+ ## (cols x rows) for now - why? why not?
10
+
11
+ composite_count = @count - @excludes.size
12
+ cols, rows = case composite_count
13
+ when 99 then [10, 10]
14
+ when 100 then [10, 10]
15
+ when 150 then [15, 10]
16
+ when 314 then [15, 21]
17
+ when 500 then [25, 20]
18
+ when 1000 then [25, 40]
19
+ when 3000 then [100, 30] ## or use 50*60 - why? why not?
20
+ when 3500 then [100, 35] ## or use 50*x ??
21
+ when 3979 then [100, 40]
22
+ when 4000 then [100, 40] ## or use 50x80 - why? why not?
23
+ when 5000 then [100, 50] ## or use 50x100 - why? why not?
24
+ when 5555 then [100, 56] # 5600 (45 left empty)
25
+ when 6969 then [100, 70] # 7000 (31 left empty)
26
+ when 10000 then [100, 100]
27
+ else
28
+ raise ArgumentError, "sorry - unknown composite count #{composite_count}/#{@count} for now"
29
+ end
30
+
31
+ composite = ImageComposite.new( cols, rows,
32
+ width: @width,
33
+ height: @height )
34
+
35
+ each_image do |img, id|
36
+ puts "==> #{id}"
37
+ composite << img
38
+ end
39
+
40
+
41
+
42
+ composite.save( "./#{@slug}/tmp/#{@slug}-#{@width}x#{@height}.png" )
43
+
44
+ if composite_count < 1000
45
+ composite.zoom(2).save( "./#{@slug}/tmp/#{@slug}-#{@width}x#{@height}@2x.png" )
46
+ end
47
+ end
48
+
49
+
50
+
51
+
52
+ def calc_attribute_counters ## todo/check: use a different name _counts/_stats etc - why? why not?
53
+
54
+ attributes_by_count = { count: 0,
55
+ by_count: Hash.new(0)
56
+ }
57
+ counter = {}
58
+
59
+
60
+ each_meta do |meta, id| ## todo/fix: change id to index
61
+ traits = meta.traits
62
+ # print "#{traits.size} - "
63
+ # pp traits
64
+
65
+ print "#{id}.." if id % 100 == 0 ## print progress report
66
+
67
+ attributes_by_count[ :count ] +=1
68
+ attributes_by_count[ :by_count ][ traits.size ] += 1
69
+
70
+ traits.each do |trait_type, trait_value|
71
+ trait_type = _normalize_trait_type( trait_type )
72
+ trait_value = _normalize_trait_value( trait_value )
73
+
74
+
75
+ rec = counter[ trait_type ] ||= { count: 0,
76
+ by_type: Hash.new(0)
77
+ }
78
+ rec[ :count ] +=1
79
+ rec[ :by_type ][ trait_value ] += 1
80
+ end
81
+ end
82
+
83
+ print "\n"
84
+ puts
85
+
86
+ ## return all-in-one hash
87
+ {
88
+ total: attributes_by_count,
89
+ traits: counter,
90
+ }
91
+ end
92
+
93
+
94
+ def dump_attributes
95
+ stats = calc_attribute_counters
96
+
97
+ total = stats[:total]
98
+ counter = stats[:traits]
99
+
100
+ puts
101
+ puts "attribute usage / counts:"
102
+ pp total
103
+ puts
104
+
105
+ puts "#{counter.size} attribute(s):"
106
+ counter.each do |trait_name, trait_rec|
107
+ puts " #{trait_name} #{trait_rec[:count]} (#{trait_rec[:by_type].size} uniques)"
108
+ end
109
+
110
+ puts
111
+ pp counter
112
+ end
113
+
114
+
115
+
116
+
117
+ ## order - allow "custom" attribute order export
118
+ ## renames - allow renames of attributes
119
+ def export_attributes(
120
+ order: [],
121
+ renames: {}
122
+ )
123
+
124
+ ## step 1: get counters
125
+ stats = calc_attribute_counters
126
+
127
+ total = stats[:total]
128
+ counter = stats[:traits]
129
+
130
+ puts
131
+ puts "attribute usage / counts:"
132
+ pp total
133
+ puts
134
+
135
+ puts "#{counter.size} attribute(s):"
136
+ counter.each do |trait_name, trait_rec|
137
+ puts " #{trait_name} #{trait_rec[:count]} (#{trait_rec[:by_type].size} uniques)"
138
+ end
139
+
140
+
141
+ trait_names = []
142
+ trait_names += order ## get attributes if any in pre-defined order
143
+ counter.each do |trait_name, _|
144
+ if trait_names.include?( trait_name )
145
+ next ## skip already included
146
+ else
147
+ trait_names << trait_name
148
+ end
149
+ end
150
+
151
+
152
+ recs = []
153
+
154
+
155
+ ## step 2: get tabular data
156
+ each_meta do |meta, id| ## todo/fix: change id to index
157
+
158
+ traits = meta.traits
159
+ # print "#{traits.size} - "
160
+ # pp traits
161
+
162
+ print "#{id}.." if id % 100 == 0 ## print progress report
163
+
164
+ ## setup empty hash table (with all attributes)
165
+ rec = {}
166
+
167
+ ## note: use __Slug__& __Name__
168
+ ## to avoid conflict with attribute names
169
+ ## e.g. attribute with "Name" will overwrite built-in and so on
170
+
171
+ rec['__Slug__'] = if respond_to?( :_meta_slugify )
172
+ _meta_slugify( meta, id )
173
+ else
174
+ ## default to id (six digits) as string with leading zeros
175
+ ## for easy sorting using strings
176
+ ## e.g. 1 => '000001'
177
+ ## 2 => '000002'
178
+ '%06d' % id
179
+ end
180
+
181
+ rec['__Name__'] = meta.name
182
+
183
+ ## add all attributes/traits names/keys
184
+ trait_names.reduce( rec ) { |h,value| h[value] = []; h }
185
+ ## pp rec
186
+
187
+ ## note: use an array (to allow multiple values for attributes)
188
+ traits.each do |trait_type, trait_value|
189
+ trait_type = _normalize_trait_type( trait_type )
190
+ trait_value = _normalize_trait_value( trait_value )
191
+
192
+ values = rec[ trait_type ]
193
+ values << trait_value
194
+ end
195
+ recs << rec
196
+ end
197
+ print "\n"
198
+
199
+ ## pp recs
200
+
201
+ ## flatten recs
202
+ data = []
203
+ recs.each do |rec|
204
+ row = rec.values.map do |value|
205
+ if value.is_a?( Array )
206
+ value.join( ' / ' )
207
+ else
208
+ value
209
+ end
210
+ end
211
+ data << row
212
+ end
213
+
214
+
215
+ ## sort by slug
216
+ data = data.sort {|l,r| l[0] <=> r[0] }
217
+ pp data
218
+
219
+ ### save dataset
220
+ ## note: change first colum Slug to ID - only used for "internal" sort etc.
221
+ headers = ['ID', 'Name']
222
+ headers += trait_names.map do |trait_name| ## check for renames
223
+ renames[trait_name] || trait_name
224
+ end
225
+
226
+
227
+ path = "./#{@slug}/tmp/#{@slug}.csv"
228
+ dirname = File.dirname( path )
229
+ FileUtils.mkdir_p( dirname ) unless Dir.exist?( dirname )
230
+
231
+ File.open( path, 'w:utf-8' ) do |f|
232
+ f.write( headers.join( ', ' ))
233
+ f.write( "\n" )
234
+ ## note: replace ID with our own internal running (zero-based) counter
235
+ data.each_with_index do |row,i|
236
+ f.write( ([i]+row[1..-1]).join( ', '))
237
+ f.write( "\n" )
238
+ end
239
+ end
240
+ end
241
+
242
+
243
+
244
+
245
+ #############
246
+ # "private" helpers
247
+
248
+ def _normalize_trait_type( trait_type )
249
+ if @patch && @patch[:trait_types]
250
+ @patch[:trait_types][ trait_type ] || trait_type
251
+ else
252
+ trait_type
253
+ end
254
+ end
255
+
256
+ def _normalize_trait_value( trait_value )
257
+ if @patch && @patch[:trait_values]
258
+ @patch[:trait_values][ trait_value ] || trait_value
259
+ else
260
+ trait_value
261
+ end
262
+ end
263
+
264
+
265
+
266
+
267
+ end # class Base
268
+ 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
+