artbase 0.2.1 → 0.3.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.
- checksums.yaml +4 -4
- data/Manifest.txt +0 -10
- data/Rakefile +4 -3
- data/lib/artbase/tool.rb +74 -24
- data/lib/artbase/version.rb +2 -2
- data/lib/artbase.rb +12 -78
- metadata +11 -21
- data/lib/artbase/attributes.rb +0 -83
- data/lib/artbase/collection/base.rb +0 -306
- data/lib/artbase/collection/image.rb +0 -39
- data/lib/artbase/collection/opensea.rb +0 -297
- data/lib/artbase/collection/token.rb +0 -372
- data/lib/artbase/collection.rb +0 -12
- data/lib/artbase/helper.rb +0 -169
- data/lib/artbase/image/sample.rb +0 -31
- data/lib/artbase/image.rb +0 -31
- data/lib/artbase/retry.rb +0 -41
@@ -1,372 +0,0 @@
|
|
1
|
-
|
2
|
-
class TokenCollection < Artbase::Base
|
3
|
-
|
4
|
-
|
5
|
-
#############
|
6
|
-
# (nested) Meta classes
|
7
|
-
# read meta data into struct
|
8
|
-
class Meta
|
9
|
-
def self.read( path )
|
10
|
-
new( read_json( path ))
|
11
|
-
end
|
12
|
-
|
13
|
-
|
14
|
-
def initialize( data )
|
15
|
-
@data = data
|
16
|
-
end
|
17
|
-
|
18
|
-
|
19
|
-
def name
|
20
|
-
## note: name might be an integer number e.g. 0/1/2 etc.
|
21
|
-
## e.g. see crypto pudgy punks and others?
|
22
|
-
## always auto-convert to string
|
23
|
-
@name ||= _normalize( @data['name'].to_s )
|
24
|
-
end
|
25
|
-
|
26
|
-
|
27
|
-
def description
|
28
|
-
@description ||= _normalize( @data['description'] )
|
29
|
-
end
|
30
|
-
|
31
|
-
## note: auto-convert "" (empty string) to nil
|
32
|
-
def image() _blank( @data['image'] ); end
|
33
|
-
alias_method :image_url, :image ## add image_url alias - why? why not?
|
34
|
-
|
35
|
-
|
36
|
-
def attributes
|
37
|
-
@attributes ||= begin
|
38
|
-
traits = []
|
39
|
-
## keep traits as (simple)
|
40
|
-
## ordered array of pairs for now
|
41
|
-
##
|
42
|
-
## in a step two make lookup via hash table
|
43
|
-
## or such easier / "automagic"
|
44
|
-
|
45
|
-
@data[ 'attributes' ].each do |t|
|
46
|
-
trait_type = t['trait_type'].strip
|
47
|
-
trait_value = t['value'].strip
|
48
|
-
traits << [trait_type, trait_value]
|
49
|
-
end
|
50
|
-
|
51
|
-
traits
|
52
|
-
end
|
53
|
-
end
|
54
|
-
alias_method :traits, :attributes ## keep traits alias - why? why not?
|
55
|
-
|
56
|
-
### "private" convenience / helper methods
|
57
|
-
def _normalize( str )
|
58
|
-
return if str.nil? ## check: check for nil - why? why not?
|
59
|
-
|
60
|
-
## normalize string
|
61
|
-
## remove leading and trailing spaces
|
62
|
-
## collapse two and more spaces into one
|
63
|
-
## change unicode space to ascii
|
64
|
-
str = str.gsub( "\u{00a0}", ' ' )
|
65
|
-
str = str.strip.gsub( /[ ]{2,}/, ' ' )
|
66
|
-
str
|
67
|
-
end
|
68
|
-
|
69
|
-
def _blank( o ) ## auto-convert "" (empty string) into nil
|
70
|
-
if o && o.strip.empty?
|
71
|
-
nil
|
72
|
-
else
|
73
|
-
o
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end # (nested) class Meta
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
attr_reader :slug, :count
|
82
|
-
|
83
|
-
def initialize( slug, count,
|
84
|
-
token_base:,
|
85
|
-
image_base: nil,
|
86
|
-
image_base_id_format: nil,
|
87
|
-
format:,
|
88
|
-
source:,
|
89
|
-
top_x: 0,
|
90
|
-
top_y: 0,
|
91
|
-
center_x: true,
|
92
|
-
center_y: true,
|
93
|
-
excludes: [],
|
94
|
-
offset: 0 ) # check: rename count to items or such - why? why not?
|
95
|
-
@slug = slug
|
96
|
-
@count = count
|
97
|
-
@offset = offset ## starting by default at 0 (NOT 1 or such)
|
98
|
-
|
99
|
-
@token_base = token_base
|
100
|
-
@image_base = image_base
|
101
|
-
@image_base_id_format = image_base_id_format
|
102
|
-
|
103
|
-
@width, @height = _parse_dimension( format )
|
104
|
-
|
105
|
-
|
106
|
-
## note: allow multiple source formats / dimensions
|
107
|
-
### e.g. convert 512x512 into [ [512,512] ]
|
108
|
-
##
|
109
|
-
source = [source] unless source.is_a?( Array )
|
110
|
-
@sources = source.map { |dimension| _parse_dimension( dimension ) }
|
111
|
-
|
112
|
-
@top_x = top_x ## more (down)sampling / pixelate options
|
113
|
-
@top_y = top_y
|
114
|
-
@center_x = center_x
|
115
|
-
@center_y = center_y
|
116
|
-
|
117
|
-
@excludes = excludes
|
118
|
-
end
|
119
|
-
|
120
|
-
|
121
|
-
## e.g. convert dimension (width x height) "24x24" or "24 x 24" to [24,24]
|
122
|
-
def _parse_dimension( str )
|
123
|
-
str.split( /x/i ).map { |str| str.strip.to_i }
|
124
|
-
end
|
125
|
-
|
126
|
-
|
127
|
-
def _range( offset: 0 ) ## return "default" range - make "private" helper public - why? why not?
|
128
|
-
## note: range uses three dots (...) exclusive (NOT inclusive) range
|
129
|
-
## e.g. 0...100 => [0,..,99]
|
130
|
-
## 1...101 => [1,..,100]
|
131
|
-
##
|
132
|
-
## note: allow offset argument
|
133
|
-
## (to start with different offset - note: in addition to builtin 0/1 offset)
|
134
|
-
|
135
|
-
(0+@offset+offset...@count+@offset)
|
136
|
-
end
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
def each_image( range=_range,
|
141
|
-
exclude: true, &blk )
|
142
|
-
range.each do |id|
|
143
|
-
####
|
144
|
-
# filter out/skip
|
145
|
-
# if exclude && @excludes.include?( id )
|
146
|
-
# puts " skipping / exclude #{id}..."
|
147
|
-
# next
|
148
|
-
# end
|
149
|
-
|
150
|
-
puts "==> #{id}"
|
151
|
-
img = Image.read( "./#{@slug}/#{@width}x#{@height}/#{id}.png" )
|
152
|
-
blk.call( img, id )
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
|
157
|
-
def each_meta( range=_range,
|
158
|
-
exclude: true, &blk )
|
159
|
-
range.each do |id| ## check: change/rename id to index - why? why not?
|
160
|
-
meta = Meta.read( "./#{@slug}/token/#{id}.json" )
|
161
|
-
|
162
|
-
####
|
163
|
-
# filter out/skip
|
164
|
-
# if exclude && @excludes.include?( meta.name )
|
165
|
-
# puts " skipping / exclude #{id} >#{meta.name}<..."
|
166
|
-
# next
|
167
|
-
# end
|
168
|
-
|
169
|
-
blk.call( meta, id )
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
def pixelate( range=_range, exclude: true,
|
178
|
-
force: false,
|
179
|
-
debug: false,
|
180
|
-
zoom: nil )
|
181
|
-
|
182
|
-
range.each do |id|
|
183
|
-
|
184
|
-
if exclude && @excludes.include?( id )
|
185
|
-
puts " skipping #{id}; listed in excludes #{@excludes.inspect}"
|
186
|
-
next
|
187
|
-
end
|
188
|
-
|
189
|
-
outpath = "./#{@slug}/#{@width}x#{@height}/#{id}.png"
|
190
|
-
if !force && File.exist?( outpath )
|
191
|
-
next ## note: skip if file already exists
|
192
|
-
end
|
193
|
-
|
194
|
-
center_x = if @center_x.is_a?( Proc ) then @center_x.call( id ); else @center_x; end
|
195
|
-
center_y = if @center_y.is_a?( Proc ) then @center_y.call( id ); else @center_y; end
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
puts "==> #{id} - reading / decoding #{id} ..."
|
200
|
-
start = Time.now
|
201
|
-
|
202
|
-
img = Image.read( "./#{@slug}/token-i/#{id}.png" )
|
203
|
-
|
204
|
-
stop = Time.now
|
205
|
-
diff = stop - start
|
206
|
-
|
207
|
-
puts " in #{diff} sec(s)\n"
|
208
|
-
|
209
|
-
|
210
|
-
source = nil
|
211
|
-
@sources.each do |source_width, source_height|
|
212
|
-
if img.width == source_width && img.height == source_height
|
213
|
-
source = [source_width, source_height]
|
214
|
-
break
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
|
219
|
-
if source
|
220
|
-
source_width = source[0]
|
221
|
-
source_height = source[1]
|
222
|
-
|
223
|
-
steps_x = Image.calc_sample_steps( source_width-@top_x, @width, center: center_x )
|
224
|
-
steps_y = Image.calc_sample_steps( source_height-@top_y, @height, center: center_y )
|
225
|
-
|
226
|
-
pix = if debug
|
227
|
-
img.pixelate_debug( steps_x, steps_y,
|
228
|
-
top_x: @top_x,
|
229
|
-
top_y: @top_y )
|
230
|
-
else
|
231
|
-
img.pixelate( steps_x, steps_y,
|
232
|
-
top_x: @top_x,
|
233
|
-
top_y: @top_y )
|
234
|
-
end
|
235
|
-
## todo/check: keep usingu slug e.g. 0001.png or "plain" 1.png - why? why not?
|
236
|
-
## slug = "%04d" % id
|
237
|
-
pix.save( outpath )
|
238
|
-
|
239
|
-
if zoom
|
240
|
-
outpath = "./#{@slug}/#{@width}x#{@height}/#{id}@#{zoom}x.png"
|
241
|
-
pix.zoom( zoom ).save( outpath )
|
242
|
-
end
|
243
|
-
else
|
244
|
-
puts "!! ERROR - unknown/unsupported dimension - #{img.width}x#{img.height}; sorry - tried:"
|
245
|
-
pp @sources
|
246
|
-
exit 1
|
247
|
-
end
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
def meta_url( id: )
|
254
|
-
src = @token_base.gsub( '{id}', id.to_s )
|
255
|
-
|
256
|
-
## quick ipfs (interplanetary file system) hack - make more reusabele!!!
|
257
|
-
src = handle_ipfs( src )
|
258
|
-
src
|
259
|
-
end
|
260
|
-
alias_method :token_url, :meta_url
|
261
|
-
|
262
|
-
|
263
|
-
def image_url( id:,
|
264
|
-
direct: @image_base ? true : false )
|
265
|
-
src = if direct && @image_base
|
266
|
-
###
|
267
|
-
## todo/fix:
|
268
|
-
## change image_base_id_format
|
269
|
-
## to image_base proc with para id and call proc!!!!
|
270
|
-
if @image_base_id_format
|
271
|
-
@image_base.gsub( '{id}', @image_base_id_format % id )
|
272
|
-
else
|
273
|
-
@image_base.gsub( '{id}', id.to_s )
|
274
|
-
end
|
275
|
-
else
|
276
|
-
## todo/check - change/rename data to meta - why? why not?
|
277
|
-
data = Meta.read( "./#{@slug}/token/#{id}.json" )
|
278
|
-
|
279
|
-
meta_name = data.name
|
280
|
-
meta_image = data.image
|
281
|
-
|
282
|
-
puts "==> #{id} - #{@slug}..."
|
283
|
-
puts " name: #{meta_name}"
|
284
|
-
puts " image: #{meta_image}"
|
285
|
-
meta_image
|
286
|
-
end
|
287
|
-
src
|
288
|
-
|
289
|
-
## quick ipfs (interplanetary file system) hack - make more reusabele!!!
|
290
|
-
src = handle_ipfs( src )
|
291
|
-
src
|
292
|
-
end
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
def download_meta( range=_range, force: false )
|
297
|
-
start = Time.now
|
298
|
-
delay_in_s = 0.3
|
299
|
-
|
300
|
-
range.each do |id|
|
301
|
-
outpath = "./#{@slug}/token/#{id}.json"
|
302
|
-
if !force && File.exist?( outpath )
|
303
|
-
next ## note: skip if file already exists
|
304
|
-
end
|
305
|
-
|
306
|
-
dirname = File.dirname( outpath )
|
307
|
-
FileUtils.mkdir_p( dirname ) unless Dir.exist?( dirname )
|
308
|
-
|
309
|
-
puts "==> #{id} - #{@slug}..."
|
310
|
-
|
311
|
-
token_src = meta_url( id: id )
|
312
|
-
copy_json( token_src, outpath )
|
313
|
-
|
314
|
-
stop = Time.now
|
315
|
-
diff = stop - start
|
316
|
-
puts " download token metadata in #{diff} sec(s)"
|
317
|
-
|
318
|
-
mins = diff / 60 ## todo - use floor or such?
|
319
|
-
secs = diff % 60
|
320
|
-
puts "up #{mins} mins #{secs} secs (total #{diff} secs)"
|
321
|
-
|
322
|
-
puts "sleeping #{delay_in_s}s..."
|
323
|
-
sleep( delay_in_s )
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
|
328
|
-
## note: default to direct true if image_base present/availabe
|
329
|
-
## otherwise to false
|
330
|
-
## todo/check: change/rename force para to overwrite - why? why not?
|
331
|
-
def download_images( range=_range, force: false,
|
332
|
-
direct: @image_base ? true : false )
|
333
|
-
start = Time.now
|
334
|
-
delay_in_s = 0.3
|
335
|
-
|
336
|
-
range.each do |id|
|
337
|
-
|
338
|
-
## note: skip if (downloaded) file already exists
|
339
|
-
skip = false
|
340
|
-
if !force
|
341
|
-
['png', 'gif', 'jgp', 'svg'].each do |format|
|
342
|
-
if File.exist?( "./#{@slug}/token-i/#{id}.#{format}" )
|
343
|
-
skip = true
|
344
|
-
break
|
345
|
-
end
|
346
|
-
end
|
347
|
-
end
|
348
|
-
next if skip
|
349
|
-
|
350
|
-
image_src = image_url( id: id, direct: direct )
|
351
|
-
|
352
|
-
## note: will auto-add format file extension (e.g. .png, .jpg)
|
353
|
-
## depending on http content type!!!!!
|
354
|
-
start_copy = Time.now
|
355
|
-
copy_image( image_src, "./#{@slug}/token-i/#{id}" )
|
356
|
-
|
357
|
-
stop = Time.now
|
358
|
-
|
359
|
-
diff = stop - start_copy
|
360
|
-
puts " download image in #{diff} sec(s)"
|
361
|
-
|
362
|
-
diff = stop - start
|
363
|
-
mins = diff / 60 ## todo - use floor or such?
|
364
|
-
secs = diff % 60
|
365
|
-
puts "up #{mins} mins #{secs} secs (total #{diff} secs)"
|
366
|
-
|
367
|
-
puts "sleeping #{delay_in_s}s..."
|
368
|
-
sleep( delay_in_s )
|
369
|
-
end
|
370
|
-
end
|
371
|
-
|
372
|
-
end # class TokenCollection
|
data/lib/artbase/collection.rb
DELETED
data/lib/artbase/helper.rb
DELETED
@@ -1,169 +0,0 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
def slugify( name )
|
5
|
-
name.downcase.gsub( /[^a-z0-9 ()$_-]/ ) do |_|
|
6
|
-
puts " !! WARN: asciify - found (and removing) non-ascii char >#{Regexp.last_match}<"
|
7
|
-
'' ## remove - use empty string
|
8
|
-
end.gsub( ' ', '_')
|
9
|
-
end
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
=begin
|
14
|
-
moved/ use Image.convert !!! remove here
|
15
|
-
def convert_images( collection, from: 'jpg',
|
16
|
-
to: 'png',
|
17
|
-
dir: 'i',
|
18
|
-
overwrite: true )
|
19
|
-
files = Dir.glob( "./#{collection}/#{dir}/*.#{from}" )
|
20
|
-
puts "==> converting #{files.size} image(s) from #{from} to #{to}"
|
21
|
-
|
22
|
-
files.each_with_index do |file,i|
|
23
|
-
dirname = File.dirname( file )
|
24
|
-
extname = File.extname( file )
|
25
|
-
basename = File.basename( file, extname )
|
26
|
-
|
27
|
-
## skip convert if target / dest file already exists
|
28
|
-
next if overwrite == false && File.exist?( "#{dirname}/#{basename}.#{to}" )
|
29
|
-
|
30
|
-
|
31
|
-
cmd = "magick convert #{dirname}/#{basename}.#{from} #{dirname}/#{basename}.#{to}"
|
32
|
-
|
33
|
-
puts " [#{i+1}/#{files.size}] - #{cmd}"
|
34
|
-
system( cmd )
|
35
|
-
|
36
|
-
if from == 'gif'
|
37
|
-
## assume multi-images for gif
|
38
|
-
## save image-0.png to image.png
|
39
|
-
path0 = "#{dirname}/#{basename}-0.#{to}"
|
40
|
-
path = "#{dirname}/#{basename}.#{to}"
|
41
|
-
|
42
|
-
puts " saving #{path0} to #{path}..."
|
43
|
-
|
44
|
-
blob = File.open( path0, 'rb' ) { |f| f.read }
|
45
|
-
File.open( path, 'wb' ) { |f| f.write( blob ) }
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
=end
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
def copy_json( src, dest )
|
58
|
-
uri = URI.parse( src )
|
59
|
-
|
60
|
-
http = Net::HTTP.new( uri.host, uri.port )
|
61
|
-
|
62
|
-
puts "[debug] GET #{uri.request_uri} uri=#{uri}"
|
63
|
-
|
64
|
-
headers = { 'User-Agent' => "ruby v#{RUBY_VERSION}" }
|
65
|
-
|
66
|
-
|
67
|
-
request = Net::HTTP::Get.new( uri.request_uri, headers )
|
68
|
-
if uri.instance_of? URI::HTTPS
|
69
|
-
http.use_ssl = true
|
70
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
71
|
-
end
|
72
|
-
|
73
|
-
response = http.request( request )
|
74
|
-
|
75
|
-
if response.code == '200'
|
76
|
-
puts "#{response.code} #{response.message}"
|
77
|
-
puts " content_type: #{response.content_type}, content_length: #{response.content_length}"
|
78
|
-
|
79
|
-
text = response.body.to_s
|
80
|
-
text = text.force_encoding( Encoding::UTF_8 )
|
81
|
-
|
82
|
-
data = JSON.parse( text )
|
83
|
-
|
84
|
-
File.open( dest, "w:utf-8" ) do |f|
|
85
|
-
f.write( JSON.pretty_generate( data ) )
|
86
|
-
end
|
87
|
-
else
|
88
|
-
puts "!! error:"
|
89
|
-
puts "#{response.code} #{response.message}"
|
90
|
-
exit 1
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
|
95
|
-
def copy_image( src, dest,
|
96
|
-
dump_headers: false )
|
97
|
-
uri = URI.parse( src )
|
98
|
-
|
99
|
-
http = Net::HTTP.new( uri.host, uri.port )
|
100
|
-
|
101
|
-
puts "[debug] GET #{uri.request_uri} uri=#{uri}"
|
102
|
-
|
103
|
-
headers = { 'User-Agent' => "ruby v#{RUBY_VERSION}" }
|
104
|
-
|
105
|
-
request = Net::HTTP::Get.new( uri.request_uri, headers )
|
106
|
-
if uri.instance_of? URI::HTTPS
|
107
|
-
http.use_ssl = true
|
108
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
109
|
-
end
|
110
|
-
|
111
|
-
response = http.request( request )
|
112
|
-
|
113
|
-
if response.code == '200'
|
114
|
-
puts "#{response.code} #{response.message}"
|
115
|
-
|
116
|
-
content_type = response.content_type
|
117
|
-
content_length = response.content_length
|
118
|
-
puts " content_type: #{content_type}, content_length: #{content_length}"
|
119
|
-
|
120
|
-
if dump_headers ## for debugging dump headers
|
121
|
-
headers = response.each_header.to_h
|
122
|
-
puts "htttp respone headers:"
|
123
|
-
pp headers
|
124
|
-
end
|
125
|
-
|
126
|
-
|
127
|
-
format = if content_type =~ %r{image/jpeg}i
|
128
|
-
'jpg'
|
129
|
-
elsif content_type =~ %r{image/png}i
|
130
|
-
'png'
|
131
|
-
elsif content_type =~ %r{image/gif}i
|
132
|
-
'gif'
|
133
|
-
elsif content_type =~ %r{image/svg}i
|
134
|
-
'svg'
|
135
|
-
else
|
136
|
-
puts "!! error:"
|
137
|
-
puts " unknown image format content type: >#{content_type}<"
|
138
|
-
exit 1
|
139
|
-
end
|
140
|
-
|
141
|
-
## make sure path exits - autocreate dirs
|
142
|
-
## make sure path exists
|
143
|
-
dirname = File.dirname( "#{dest}.#{format}" )
|
144
|
-
FileUtils.mkdir_p( dirname ) unless Dir.exist?( dirname )
|
145
|
-
|
146
|
-
if format == 'svg'
|
147
|
-
## save as text (note: assume utf-8 encoding for now)
|
148
|
-
text = response.body.to_s
|
149
|
-
text = text.force_encoding( Encoding::UTF_8 )
|
150
|
-
|
151
|
-
File.open( "#{dest}.svg", 'w:utf-8' ) do |f|
|
152
|
-
f.write( text )
|
153
|
-
end
|
154
|
-
else
|
155
|
-
## save as binary
|
156
|
-
File.open( "#{dest}.#{format}", 'wb' ) do |f|
|
157
|
-
f.write( response.body )
|
158
|
-
end
|
159
|
-
end
|
160
|
-
else
|
161
|
-
puts "!! error:"
|
162
|
-
puts "#{response.code} #{response.message}"
|
163
|
-
exit 1
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
data/lib/artbase/image/sample.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
module Pixelart
|
2
|
-
|
3
|
-
class Image
|
4
|
-
|
5
|
-
###
|
6
|
-
# add common
|
7
|
-
# pixel(ate) steps/offsets (for re/down/sampling)
|
8
|
-
DOwNSAMPLING_STEPS = {
|
9
|
-
'24x24' => {
|
10
|
-
'269x269' => Image.calc_sample_steps( 269, 24 ), # width (269px), new_width (24px)
|
11
|
-
'512x512' => Image.calc_sample_steps( 512, 24 ), # width (512px), new_width (24px)
|
12
|
-
},
|
13
|
-
'32x32' => {
|
14
|
-
'320x320' => Image.calc_sample_steps( 320, 32 ),
|
15
|
-
'512x512' => Image.calc_sample_steps( 512, 32 ),
|
16
|
-
},
|
17
|
-
'35x35' => {
|
18
|
-
'512x512' => Image.calc_sample_steps( 512, 35 ),
|
19
|
-
},
|
20
|
-
'60x60' => {
|
21
|
-
'512x512' => Image.calc_sample_steps( 512, 60 ),
|
22
|
-
},
|
23
|
-
'80x80' => {
|
24
|
-
'512x512' => Image.calc_sample_steps( 512, 80 ),
|
25
|
-
},
|
26
|
-
}
|
27
|
-
|
28
|
-
end # class Image
|
29
|
-
end # module Pixelart
|
30
|
-
|
31
|
-
|
data/lib/artbase/image.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
######################
|
2
|
-
# pixelart image extensions
|
3
|
-
# move upstream!!!!!
|
4
|
-
|
5
|
-
|
6
|
-
module Pixelart
|
7
|
-
class ImageComposite
|
8
|
-
def add_glob( glob )
|
9
|
-
files = Dir.glob( glob )
|
10
|
-
puts "#{files.size} file(s) found matching >#{glob}<"
|
11
|
-
|
12
|
-
|
13
|
-
files = files.sort
|
14
|
-
## puts files.inspect
|
15
|
-
|
16
|
-
files.each_with_index do |file,i|
|
17
|
-
puts "==> [#{i+1}/#{files.size}] - #{file}"
|
18
|
-
img = Image.read( file )
|
19
|
-
|
20
|
-
self << img ## todo/check: use add alias - why? why not?
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end # class ImageComposite
|
24
|
-
end # module Pixelart
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
require_relative 'image/sample' ## check - change to downsample/pixelate - why? why not?
|
29
|
-
|
30
|
-
|
31
|
-
|
data/lib/artbase/retry.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
|
2
|
-
## for more ideas on retry
|
3
|
-
## see https://github.com/ooyala/retries
|
4
|
-
|
5
|
-
|
6
|
-
## todo/check: use a different name than retry - why? why not?
|
7
|
-
def retry_on_error( max_tries: 3, &block )
|
8
|
-
errors = []
|
9
|
-
delay = 3 ## 3 secs
|
10
|
-
|
11
|
-
begin
|
12
|
-
block.call
|
13
|
-
|
14
|
-
## note: add more exception here (separated by comma) like
|
15
|
-
## rescue Errno::ETIMEDOUT, Errno::ECONNREFUSED => e
|
16
|
-
rescue Net::ReadTimeout => e
|
17
|
-
## (re)raise (use raise with arguments or such - why? why not?)
|
18
|
-
raise if errors.size >= max_tries
|
19
|
-
|
20
|
-
## ReadTimeout, a subclass of Timeout::Error, is raised if a chunk of the response cannot be read within the read_timeout.
|
21
|
-
## subclass of RuntimeError
|
22
|
-
## subclass of StandardError
|
23
|
-
## subclass of Exception
|
24
|
-
puts "!! ERROR - #{e}:"
|
25
|
-
pp e
|
26
|
-
|
27
|
-
errors << e
|
28
|
-
|
29
|
-
puts
|
30
|
-
puts "==> retrying (count=#{errors.size}, max_tries=#{max_tries}) in #{delay} sec(s)..."
|
31
|
-
sleep( delay )
|
32
|
-
retry
|
33
|
-
end
|
34
|
-
|
35
|
-
if errors.size > 0
|
36
|
-
puts " #{errors.size} retry attempt(s) on error(s):"
|
37
|
-
pp errors
|
38
|
-
end
|
39
|
-
|
40
|
-
errors
|
41
|
-
end
|