artbase 0.1.0 → 0.2.0

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