cryptopunks 0.0.1 → 1.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.
- checksums.yaml +4 -4
- data/Manifest.txt +6 -0
- data/README.md +230 -6
- data/Rakefile +4 -4
- data/bin/cryptopunk +17 -0
- data/bin/punk +17 -0
- data/lib/cryptopunks.rb +106 -3
- data/lib/cryptopunks/attributes.rb +147 -0
- data/lib/cryptopunks/composite.rb +62 -0
- data/lib/cryptopunks/dataset.rb +67 -0
- data/lib/cryptopunks/structs.rb +148 -0
- data/lib/cryptopunks/version.rb +3 -3
- metadata +18 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f8f5a03075399de98c5456fd8c74bcd84c2bebea84b033131351c737dd1934ba
|
4
|
+
data.tar.gz: cb75041e34f7104b4e19ab9913a66d3383273299f0a2bec10b53d2c6d428f4f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 258ce6be66ad8a06dae14aeb916e620549e50e2dc82a3d96964dbd31e7766df5205b89e630cf3c703b2dbbc52d0e14c4314751447e200ceab47fc7d8bbc81891
|
7
|
+
data.tar.gz: c5d5556a2a644a25431f666fb46aa667c0460a721e379b43e17284e4400cb3b515e34d10fa28f2105dd0b45ea5c2bb039518bd45cf59aa2e1da8e98be455871e
|
data/Manifest.txt
CHANGED
data/README.md
CHANGED
@@ -1,13 +1,238 @@
|
|
1
|
-
#
|
1
|
+
# Crypto Punks
|
2
2
|
|
3
|
-
mint your own 24×24 pixel punk images off chain from the True Official Genuine CryptoPunks™ sha256-verified original; incl. 2x/4x/8x zoom for bigger sizes
|
3
|
+
cryptopunks - mint your own 24×24 pixel punk images off chain from the True Official Genuine CryptoPunks™ sha256-verified original 10 000 unique character collection; incl. 2x/4x/8x zoom for bigger sizes
|
4
4
|
|
5
|
+
* home :: [github.com/cryptopunksnotdead/cryptopunks](https://github.com/cryptopunksnotdead/cryptopunks)
|
6
|
+
* bugs :: [github.com/cryptopunksnotdead/cryptopunks/issues](https://github.com/cryptopunksnotdead/cryptopunks/issues)
|
7
|
+
* gem :: [rubygems.org/gems/cryptopunks](https://rubygems.org/gems/cryptopunks)
|
8
|
+
* rdoc :: [rubydoc.info/gems/cryptopunks](http://rubydoc.info/gems/cryptopunks)
|
5
9
|
|
6
10
|
|
7
|
-
|
11
|
+
New to Crypto Punks?
|
12
|
+
See the [**Awesome CryptoPunks Bubble (Anno 2021) - Modern 24×24 Pixel Crypto Art on the Blockchain** »](https://github.com/cryptopunksnotdead/awesome-cryptopunks-bubble)
|
8
13
|
|
9
|
-
to be done
|
10
14
|
|
15
|
+
## Command Line
|
16
|
+
|
17
|
+
Use the `punk` (or `cryptopunk`) command line tool. Try:
|
18
|
+
|
19
|
+
```
|
20
|
+
$ punk -h
|
21
|
+
```
|
22
|
+
|
23
|
+
resulting in:
|
24
|
+
|
25
|
+
```
|
26
|
+
Usage: cryptopunk [options] IDs
|
27
|
+
Mint punk characters from composite (./punks.png) - for IDs use 0 to 9999
|
28
|
+
|
29
|
+
Options:
|
30
|
+
-z, --zoom=ZOOM Zoom factor x2, x4, x8, etc. (default: 1)
|
31
|
+
-d, --dir=DIR Output directory (default: .)
|
32
|
+
-f, --file=FILE True Official Genuine CryptoPunks™ composite image (default: ./punks.png)
|
33
|
+
-h, --help Prints this help
|
34
|
+
```
|
35
|
+
|
36
|
+
|
37
|
+
Step 0 - Download the True Official Genuine CryptoPunks™ composite image
|
38
|
+
|
39
|
+
One time / first time only - Download the True Official Genuine CryptoPunks™ composite
|
40
|
+
housing all 10 000 CryptoPunks
|
41
|
+
in a single 2400×2400 image (~830 kb) for free.
|
42
|
+
See [`punks.png` »](https://github.com/larvalabs/cryptopunks/blob/master/punks.png)
|
43
|
+
|
44
|
+
|
45
|
+

|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
Now let's give it a try. Let's mint punk #0, #2890, and #8219:
|
51
|
+
|
52
|
+
```
|
53
|
+
$ punk 0 2890 8219
|
54
|
+
```
|
55
|
+
|
56
|
+
printing:
|
57
|
+
|
58
|
+
```
|
59
|
+
==> reading >./punks.png<...
|
60
|
+
>ac39af4793119ee46bbff351d8cb6b5f23da60222126add4268e261199a2921b< SHA256 hash matching
|
61
|
+
✓ True Official Genuine CryptoPunks™ verified
|
62
|
+
==> (1/3) minting punk #0; writing to >./punk-0000.png<...
|
63
|
+
==> (2/3) minting punk #2890; writing to >./punk-2890.png<...
|
64
|
+
==> (3/3) minting punk #8219; writing to >./punk-8219.png<...
|
65
|
+
```
|
66
|
+
|
67
|
+
And voila!
|
68
|
+
|
69
|
+

|
70
|
+

|
71
|
+

|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
**Bonus: Try the `-z/--zoom` factor x2, x4, x8, etc.**
|
76
|
+
|
77
|
+
Let's give it a try. Let's mint punk #0, #2890, and #8219 in 2x format:
|
78
|
+
|
79
|
+
```
|
80
|
+
$ punk --zoom 2 0 2890 8219
|
81
|
+
# -or-
|
82
|
+
$ punk -z2 0 2890 8219
|
83
|
+
```
|
84
|
+
|
85
|
+
printing:
|
86
|
+
|
87
|
+
```
|
88
|
+
==> reading >./punks.png<...
|
89
|
+
>ac39af4793119ee46bbff351d8cb6b5f23da60222126add4268e261199a2921b< SHA256 hash matching
|
90
|
+
✓ True Official Genuine CryptoPunks™ verified
|
91
|
+
setting zoom to 2x
|
92
|
+
==> (1/3) minting punk #0; writing to >punk-0000x2.png<...
|
93
|
+
==> (2/3) minting punk #2890; writing to >punk-2890x2.png<...
|
94
|
+
==> (3/3) minting punk #8219; writing to >punk-8219x2.png<...
|
95
|
+
```
|
96
|
+
|
97
|
+
And voila!
|
98
|
+
|
99
|
+

|
100
|
+

|
101
|
+

|
102
|
+
|
103
|
+
And x4:
|
104
|
+
|
105
|
+

|
106
|
+

|
107
|
+

|
108
|
+
|
109
|
+
|
110
|
+
And x8:
|
111
|
+
|
112
|
+

|
113
|
+

|
114
|
+

|
115
|
+
|
116
|
+
|
117
|
+
And so on.
|
118
|
+
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
## 10 000 More Punks - Unauthorized? No Way?!- Fuck the Establishment - Yes, You Can - Do-It-Yourself - Use Your Own Collections
|
123
|
+
|
124
|
+
|
125
|
+
Use the `-f, --file=FILE` option
|
126
|
+
to pass along any unauthorized edition.
|
127
|
+
Only make sure all punks are lined-up left-to-right, top-to-bottom
|
128
|
+
in the 24x24 pixel format in the composite image.
|
129
|
+
|
130
|
+
|
131
|
+
Let's try the 10 000 More Punks series housing punks in
|
132
|
+
packs of a hundred each. Let's have a looksie at the first 100
|
133
|
+
in the series.
|
134
|
+
|
135
|
+
|
136
|
+

|
137
|
+
|
138
|
+
|
139
|
+
|
140
|
+
Let's mint punk #0, #19, #50, and #89
|
141
|
+
and let's add an offset of 10000
|
142
|
+
(to start counting at 10000 instead of 0):
|
143
|
+
|
144
|
+
```
|
145
|
+
$ punk 0 18 40 88 --file ./more-punks-1.png --offset 10000
|
146
|
+
```
|
147
|
+
|
148
|
+
printing:
|
149
|
+
|
150
|
+
```
|
151
|
+
==> reading >./more-punks-1.png<...
|
152
|
+
240x240 (height x width)
|
153
|
+
==> (1/4) minting punk #10000; writing to >./punk-10000.png<...
|
154
|
+
==> (2/4) minting punk #10018; writing to >./punk-10018.png<...
|
155
|
+
==> (3/4) minting punk #10040; writing to >./punk-10040.png<...
|
156
|
+
==> (4/4) minting punk #10040; writing to >./punk-10088.png<...
|
157
|
+
```
|
158
|
+
|
159
|
+
And voila!
|
160
|
+
|
161
|
+

|
162
|
+

|
163
|
+

|
164
|
+

|
165
|
+
|
166
|
+
|
167
|
+
And 4x:
|
168
|
+
|
169
|
+

|
170
|
+

|
171
|
+

|
172
|
+

|
173
|
+
|
174
|
+
|
175
|
+
|
176
|
+
|
177
|
+
Let's try the second pack - that is, punks 100 to 199 in the series.
|
178
|
+
|
179
|
+
|
180
|
+

|
181
|
+
|
182
|
+
|
183
|
+
|
184
|
+
Let's mint punk #0, #79, #80, and #90
|
185
|
+
and let's add an offset of 10100
|
186
|
+
(to start counting at 10000 plus 100 instead of 0):
|
187
|
+
|
188
|
+
```
|
189
|
+
$ punk 0 79 80 90 --file ./more-punks-2.png --offset 10100
|
190
|
+
```
|
191
|
+
|
192
|
+
printing:
|
193
|
+
|
194
|
+
```
|
195
|
+
==> reading >./more-punks-2.png<...
|
196
|
+
240x240 (height x width)
|
197
|
+
==> (1/4) minting punk #10100; writing to >./punk-10100.png<...
|
198
|
+
==> (2/4) minting punk #10179; writing to >./punk-10179.png<...
|
199
|
+
==> (3/4) minting punk #10180; writing to >./punk-10180.png<...
|
200
|
+
==> (4/4) minting punk #10190; writing to >./punk-10190.png<...
|
201
|
+
```
|
202
|
+
|
203
|
+
And voila! Super rare - world's first female alien and much more.
|
204
|
+
|
205
|
+
|
206
|
+

|
207
|
+

|
208
|
+

|
209
|
+

|
210
|
+
|
211
|
+
|
212
|
+
And 4x:
|
213
|
+
|
214
|
+

|
215
|
+

|
216
|
+

|
217
|
+

|
218
|
+
|
219
|
+
|
220
|
+
And so on.
|
221
|
+
|
222
|
+
|
223
|
+
|
224
|
+
|
225
|
+
|
226
|
+
|
227
|
+
|
228
|
+
|
229
|
+
## Usage in Your Scripts
|
230
|
+
|
231
|
+
|
232
|
+
Yes, you can mint punks in your own scripts
|
233
|
+
and much more.
|
234
|
+
See the
|
235
|
+
[**Programming CryptoPunks & Copypastas Step-by-Step Booklet / Guide »**](https://github.com/cryptopunksnotdead/programming-cryptopunks)
|
11
236
|
|
12
237
|
|
13
238
|
|
@@ -26,5 +251,4 @@ Use it as you please with no restrictions whatsoever.
|
|
26
251
|
|
27
252
|
## Questions? Comments?
|
28
253
|
|
29
|
-
|
30
|
-
Thanks!
|
254
|
+
Post them on the [CryptoPunksDev reddit](https://old.reddit.com/r/CryptoPunksDev). Thanks.
|
data/Rakefile
CHANGED
@@ -5,10 +5,10 @@ Hoe.spec 'cryptopunks' do
|
|
5
5
|
|
6
6
|
self.version = Cryptopunks::VERSION
|
7
7
|
|
8
|
-
self.summary = "cryptopunks - mint your own 24×24 pixel punk images off chain from the True Official Genuine CryptoPunks™ sha256-verified original; incl. 2x/4x/8x zoom for bigger sizes"
|
8
|
+
self.summary = "cryptopunks - mint your own 24×24 pixel punk images off chain from the True Official Genuine CryptoPunks™ sha256-verified original 10 000 unique character collection; incl. 2x/4x/8x zoom for bigger sizes"
|
9
9
|
self.description = summary
|
10
10
|
|
11
|
-
self.urls = { home: 'https://github.com/
|
11
|
+
self.urls = { home: 'https://github.com/cryptopunksnotdead/cryptopunks' }
|
12
12
|
|
13
13
|
self.author = 'Gerald Bauer'
|
14
14
|
self.email = 'wwwmake@googlegroups.com'
|
@@ -18,8 +18,8 @@ Hoe.spec 'cryptopunks' do
|
|
18
18
|
self.history_file = 'CHANGELOG.md'
|
19
19
|
|
20
20
|
self.extra_deps = [
|
21
|
-
['
|
22
|
-
['
|
21
|
+
['pixelart'],
|
22
|
+
['csvreader'],
|
23
23
|
]
|
24
24
|
|
25
25
|
self.licenses = ['Public Domain']
|
data/bin/cryptopunk
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
###################
|
4
|
+
# == DEV TIPS:
|
5
|
+
#
|
6
|
+
# For local testing run like:
|
7
|
+
#
|
8
|
+
# ruby -Ilib bin/cryptopunk
|
9
|
+
#
|
10
|
+
# Set the executable bit in Linux. Example:
|
11
|
+
#
|
12
|
+
# % chmod a+x bin/cryptopunk
|
13
|
+
#
|
14
|
+
|
15
|
+
require 'cryptopunks'
|
16
|
+
|
17
|
+
Cryptopunks.main
|
data/bin/punk
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
###################
|
4
|
+
# == DEV TIPS:
|
5
|
+
#
|
6
|
+
# For local testing run like:
|
7
|
+
#
|
8
|
+
# ruby -Ilib bin/punk
|
9
|
+
#
|
10
|
+
# Set the executable bit in Linux. Example:
|
11
|
+
#
|
12
|
+
# % chmod a+x bin/punk
|
13
|
+
#
|
14
|
+
|
15
|
+
require 'cryptopunks'
|
16
|
+
|
17
|
+
Cryptopunks.main
|
data/lib/cryptopunks.rb
CHANGED
@@ -1,9 +1,112 @@
|
|
1
|
-
|
1
|
+
## 3rd party
|
2
|
+
require 'pixelart'
|
3
|
+
require 'csvreader'
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
## extra stdlibs
|
8
|
+
require 'digest'
|
9
|
+
require 'optparse'
|
10
|
+
|
2
11
|
|
3
12
|
|
4
13
|
## our own code
|
5
14
|
require 'cryptopunks/version' # note: let version always go first
|
15
|
+
require 'cryptopunks/attributes'
|
16
|
+
require 'cryptopunks/structs'
|
17
|
+
require 'cryptopunks/composite'
|
18
|
+
require 'cryptopunks/dataset'
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
module Cryptopunks
|
23
|
+
class Tool
|
24
|
+
def run( args )
|
25
|
+
opts = { zoom: 1,
|
26
|
+
outdir: '.',
|
27
|
+
file: './punks.png',
|
28
|
+
offset: 0,
|
29
|
+
}
|
30
|
+
|
31
|
+
parser = OptionParser.new do |cmd|
|
32
|
+
cmd.banner = "Usage: punk (or cryptopunk) [options] IDs"
|
33
|
+
|
34
|
+
cmd.separator " Mint punk characters from composite (#{opts[:file]}) - for IDs use 0 to 9999"
|
35
|
+
cmd.separator ""
|
36
|
+
cmd.separator " Options:"
|
37
|
+
|
38
|
+
cmd.on("-z", "--zoom=ZOOM", "Zoom factor x2, x4, x8, etc. (default: #{opts[:zoom]})", Integer ) do |zoom|
|
39
|
+
opts[:zoom] = zoom
|
40
|
+
end
|
41
|
+
|
42
|
+
cmd.on("-d", "--dir=DIR", "Output directory (default: #{opts[:outdir]})", String ) do |outdir|
|
43
|
+
opts[:outdir] = outdir
|
44
|
+
end
|
45
|
+
|
46
|
+
cmd.on("-f", "--file=FILE", "True Official Genuine CryptoPunks™ composite image (default: #{opts[:file]})", String ) do |file|
|
47
|
+
opts[:file] = file
|
48
|
+
end
|
49
|
+
|
50
|
+
cmd.on("--offset=NUM", "Start counting at offset (default: #{opts[:offset]})", Integer ) do |offset|
|
51
|
+
opts[:offset] = offset
|
52
|
+
end
|
53
|
+
|
54
|
+
cmd.on("-h", "--help", "Prints this help") do
|
55
|
+
puts cmd
|
56
|
+
exit
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
parser.parse!( args )
|
61
|
+
|
62
|
+
puts "opts:"
|
63
|
+
pp opts
|
64
|
+
|
65
|
+
puts "==> reading >#{opts[:file]}<..."
|
66
|
+
punks = Image::Composite.read( opts[:file] )
|
67
|
+
|
68
|
+
|
69
|
+
puts " setting zoom to #{opts[:zoom]}x" if opts[:zoom] != 1
|
70
|
+
|
71
|
+
## make sure outdir exits (default is current working dir e.g. .)
|
72
|
+
FileUtils.mkdir_p( opts[:outdir] ) unless Dir.exist?( opts[:outdir] )
|
73
|
+
|
74
|
+
args.each_with_index do |arg,index|
|
75
|
+
punk_index = arg.to_i
|
76
|
+
|
77
|
+
punk = punks[ punk_index ]
|
78
|
+
|
79
|
+
punk_name = "punk-" + "%04d" % (punk_index + opts[:offset])
|
80
|
+
|
81
|
+
## if zoom - add x2,x4 or such
|
82
|
+
if opts[:zoom] != 1
|
83
|
+
punk = punk.zoom( opts[:zoom] )
|
84
|
+
punk_name << "x#{opts[:zoom]}"
|
85
|
+
end
|
86
|
+
|
87
|
+
path = "#{opts[:outdir]}/#{punk_name}.png"
|
88
|
+
puts "==> (#{index+1}/#{args.size}) minting punk ##{punk_index+opts[:offset]}; writing to >#{path}<..."
|
89
|
+
|
90
|
+
punk.save( path )
|
91
|
+
end
|
92
|
+
|
93
|
+
puts "done"
|
94
|
+
end ## method run
|
95
|
+
end # class Tool
|
96
|
+
|
97
|
+
|
98
|
+
def self.main( args=ARGV )
|
99
|
+
Tool.new.run( args )
|
100
|
+
end
|
101
|
+
end ## module Cryptopunks
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
### add some convenience shortcuts
|
106
|
+
CryptoPunks = Cryptopunks
|
107
|
+
Punks = Cryptopunks
|
108
|
+
|
109
|
+
|
6
110
|
|
7
111
|
|
8
|
-
|
9
|
-
pp Cryptopunks.root
|
112
|
+
puts Cryptopunks.banner # say hello
|
@@ -0,0 +1,147 @@
|
|
1
|
+
module Cryptopunks
|
2
|
+
|
3
|
+
##################
|
4
|
+
## 5 punk types
|
5
|
+
TYPES = [
|
6
|
+
{ name: 'Alien', limit: 9 },
|
7
|
+
{ name: 'Ape', limit: 24 },
|
8
|
+
{ name: 'Zombie', limit: 88 },
|
9
|
+
{ name: 'Female', limit: 3840 },
|
10
|
+
{ name: 'Male', limit: 6039 },
|
11
|
+
]
|
12
|
+
|
13
|
+
|
14
|
+
###
|
15
|
+
## categories used from:
|
16
|
+
## https://cryptoslam.io/cryptopunks/checklist
|
17
|
+
## see categories in urls e.g.
|
18
|
+
## - cryptopunks/eyes/horned-rim-glasses
|
19
|
+
## - cryptopunks/hair/peak-spike
|
20
|
+
## - cryptopunks/emotion/smile
|
21
|
+
## - etc.
|
22
|
+
##
|
23
|
+
|
24
|
+
#######
|
25
|
+
## 87 attributes / accessories
|
26
|
+
##
|
27
|
+
## note: does NOT include 5 punk types (that is, alien, ape, zombie, female, male)
|
28
|
+
|
29
|
+
|
30
|
+
ACCESSORY_TYPES = [
|
31
|
+
{ name: 'Mouth', accessories: [ { name: 'Cigarette', limit: 961 },
|
32
|
+
{ name: 'Pipe', limit: 317 },
|
33
|
+
{ name: 'Vape', limit: 272 },
|
34
|
+
{ name: 'Medical Mask', limit: 175 }]
|
35
|
+
},
|
36
|
+
{ name: 'Nose', accessories: [ { name: 'Clown Nose', limit: 212 }]
|
37
|
+
},
|
38
|
+
{
|
39
|
+
name: 'Hair',
|
40
|
+
accessories: [ { name: 'Wild Blonde', limit: 144 },
|
41
|
+
{ name: 'Wild Hair', limit: 447 },
|
42
|
+
{ name: 'Dark Hair', limit: 157 },
|
43
|
+
{ name: 'Stringy Hair', limit: 463 },
|
44
|
+
{ name: 'Crazy Hair', limit: 414 },
|
45
|
+
{ name: 'Messy Hair', limit: 460 },
|
46
|
+
{ name: 'Mohawk', limit: 441 },
|
47
|
+
{ name: 'Mohawk Thin', limit: 441 },
|
48
|
+
{ name: 'Mohawk Dark', limit: 429 },
|
49
|
+
{ name: 'Peak Spike', limit: 303 },
|
50
|
+
{ name: 'Frumpy Hair', limit: 442 },
|
51
|
+
{ name: 'Clown Hair Green', limit: 148 },
|
52
|
+
{ name: 'Shaved Head', limit: 300 },
|
53
|
+
{ name: 'Vampire Hair', limit: 147 },
|
54
|
+
{ name: 'Red Mohawk', limit: 147 },
|
55
|
+
{ name: 'Blonde Bob', limit: 147 },
|
56
|
+
{ name: 'Straight Hair Dark', limit: 148 },
|
57
|
+
{ name: 'Straight Hair', limit: 151 },
|
58
|
+
{ name: 'Purple Hair', limit: 165 },
|
59
|
+
{ name: 'Straight Hair Blonde', limit: 144 },
|
60
|
+
{ name: 'Wild White Hair', limit: 136 },
|
61
|
+
{ name: 'Half Shaved', limit: 147 },
|
62
|
+
{ name: 'Pigtails', limit: 94 },
|
63
|
+
{ name: 'Orange Side', limit: 68 },
|
64
|
+
{ name: 'Do-rag', limit: 300 },
|
65
|
+
{ name: 'Tiara', limit: 55 },
|
66
|
+
{ name: 'Blonde Short', limit: 129 },
|
67
|
+
{ name: 'Pink With Hat', limit: 95 },
|
68
|
+
{ name: 'Beanie', limit: 44 },
|
69
|
+
{ name: 'Headband', limit: 406 },
|
70
|
+
{ name: 'Bandana', limit: 481 },
|
71
|
+
{ name: 'Hoodie', limit: 259 },
|
72
|
+
{ name: 'Top Hat', limit: 115 },
|
73
|
+
{ name: 'Tassle Hat', limit: 178 },
|
74
|
+
{ name: 'Cap', limit: 351 },
|
75
|
+
{ name: 'Knitted Cap', limit: 419 },
|
76
|
+
{ name: 'Cap Forward', limit: 254 },
|
77
|
+
{ name: 'Police Cap', limit: 203 },
|
78
|
+
{ name: 'Fedora', limit: 186 },
|
79
|
+
{ name: 'Pilot Helmet', limit: 54 },
|
80
|
+
{ name: 'Cowboy Hat', limit: 142 }]
|
81
|
+
},
|
82
|
+
{
|
83
|
+
name: 'Beard',
|
84
|
+
accessories: [{ name: 'Normal Beard', limit: 292 },
|
85
|
+
{ name: 'Normal Beard Black', limit: 289 },
|
86
|
+
{ name: 'Front Beard Dark', limit: 260 },
|
87
|
+
{ name: 'Front Beard', limit: 273 },
|
88
|
+
{ name: 'Shadow Beard', limit: 526 },
|
89
|
+
{ name: 'Luxurious Beard', limit: 286 },
|
90
|
+
{ name: 'Big Beard', limit: 146 },
|
91
|
+
{ name: 'Chinstrap', limit: 282 },
|
92
|
+
{ name: 'Mustache', limit: 288 },
|
93
|
+
{ name: 'Muttonchops', limit: 303 },
|
94
|
+
{ name: 'Handlebars', limit: 263 },
|
95
|
+
{ name: 'Goat', limit: 295 }]
|
96
|
+
},
|
97
|
+
{
|
98
|
+
name: 'Ears',
|
99
|
+
accessories: [{ name: 'Earring', limit: 2459 }]
|
100
|
+
},
|
101
|
+
{
|
102
|
+
name: 'Eyes',
|
103
|
+
accessories: [{ name: 'Blue Eye Shadow', limit: 266 },
|
104
|
+
{ name: 'Purple Eye Shadow', limit: 262 },
|
105
|
+
{ name: 'Green Eye Shadow', limit: 271 },
|
106
|
+
{ name: 'Welding Goggles', limit: 86 },
|
107
|
+
{ name: 'VR', limit: 332 },
|
108
|
+
{ name: '3D Glasses', limit: 286 },
|
109
|
+
{ name: 'Clown Eyes Blue', limit: 384 },
|
110
|
+
{ name: 'Clown Eyes Green', limit: 382 },
|
111
|
+
{ name: 'Small Shades', limit: 378 },
|
112
|
+
{ name: 'Regular Shades', limit: 527 },
|
113
|
+
{ name: 'Big Shades', limit: 535 },
|
114
|
+
{ name: 'Classic Shades', limit: 502 },
|
115
|
+
{ name: 'Nerd Glasses', limit: 572 },
|
116
|
+
{ name: 'Horned Rim Glasses', limit: 535 },
|
117
|
+
{ name: 'Eye Mask', limit: 293 },
|
118
|
+
{ name: 'Eye Patch', limit: 461 }]
|
119
|
+
},
|
120
|
+
{
|
121
|
+
name: 'Lips',
|
122
|
+
accessories: [{ name: 'Purple Lipstick', limit: 655 },
|
123
|
+
{ name: 'Black Lipstick', limit: 617 },
|
124
|
+
{ name: 'Hot Lipstick', limit: 696 } ]
|
125
|
+
},
|
126
|
+
{
|
127
|
+
name: 'Face',
|
128
|
+
accessories: [{ name: 'Spots', limit: 124 },
|
129
|
+
{ name: 'Mole', limit: 644 }]
|
130
|
+
},
|
131
|
+
{
|
132
|
+
name: 'Neck',
|
133
|
+
accessories: [{ name: 'Choker', limit: 48 },
|
134
|
+
{ name: 'Silver Chain', limit: 156 },
|
135
|
+
{ name: 'Gold Chain', limit: 169 }]
|
136
|
+
},
|
137
|
+
{ name: 'Cheeks', accessories: [{ name: 'Rosy Cheeks', limit: 128 }]
|
138
|
+
},
|
139
|
+
{ name: 'Teeth', accessories: [{ name: 'Buck Teeth', limit: 78 }]
|
140
|
+
},
|
141
|
+
{ name: 'Emotion', accessories: [{ name: 'Frown', limit: 261 },
|
142
|
+
{ name: 'Smile', limit: 238 }]
|
143
|
+
}
|
144
|
+
]
|
145
|
+
|
146
|
+
|
147
|
+
end # module Cryptopunks
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Cryptopunks
|
2
|
+
class Image
|
3
|
+
class Composite ## nest Composite inside Image - why? why not?
|
4
|
+
|
5
|
+
|
6
|
+
def self.read( path='./punks.png' )
|
7
|
+
data = File.open( path, 'rb' ) { |f| f.read }
|
8
|
+
new( data )
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
PUNK_HEIGHT = 24
|
13
|
+
PUNK_WIDTH = 24
|
14
|
+
|
15
|
+
PUNK_HASH = 'ac39af4793119ee46bbff351d8cb6b5f23da60222126add4268e261199a2921b'
|
16
|
+
|
17
|
+
|
18
|
+
def initialize( data )
|
19
|
+
@punks = ChunkyPNG::Image.from_blob( data )
|
20
|
+
puts " #{@punks.height}x#{@punks.width} (height x width)"
|
21
|
+
|
22
|
+
@punk_rows = @punks.width / PUNK_WIDTH ## e.g. 2400/24 = 100
|
23
|
+
@punk_cols = @punks.height / PUNK_HEIGHT ## e.g. 2400/24 = 100
|
24
|
+
@punk_count = @punk_rows * @punk_cols ## ## 10000 = 100x100 (2400x2400 pixel)
|
25
|
+
|
26
|
+
## check sha256 checksum
|
27
|
+
@hexdigest = sha256( data )
|
28
|
+
if original?
|
29
|
+
puts " >#{@hexdigest}< SHA256 hash matching"
|
30
|
+
puts " ✓ True Official Genuine CryptoPunks™ verified"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def sha256( data )
|
36
|
+
## todo/check: or just use Digest::SHA256.hexdigest - why? why not?
|
37
|
+
Digest::SHA256.digest( data ).unpack( 'H*' )[0]
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def hexdigest() @hexdigest end
|
42
|
+
|
43
|
+
def verify?() @hexdigest == PUNK_HASH; end
|
44
|
+
alias_method :genuine?, :verify?
|
45
|
+
alias_method :original?, :verify?
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
def size() @punk_count; end
|
50
|
+
|
51
|
+
|
52
|
+
def punk( index )
|
53
|
+
y, x = index.divmod( @punk_rows )
|
54
|
+
img = @punks.crop( x*PUNK_WIDTH, y*PUNK_HEIGHT, PUNK_WIDTH, PUNK_HEIGHT )
|
55
|
+
Pixelart::Image.new( img.width, img.height, img ) ## wrap in pixelart image
|
56
|
+
end
|
57
|
+
alias_method :[], :punk
|
58
|
+
|
59
|
+
|
60
|
+
end ## class Composite
|
61
|
+
end ## class Image
|
62
|
+
end ## module Cryptopunks
|
@@ -0,0 +1,67 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Cryptopunks
|
4
|
+
module Dataset
|
5
|
+
|
6
|
+
def self.read( path='./datasets/punks/*.csv' )
|
7
|
+
|
8
|
+
datasets = Dir.glob( path )
|
9
|
+
#=> ["./datasets/punks/0-999.csv",
|
10
|
+
# "./datasets/punks/1000-1999.csv",
|
11
|
+
# "./datasets/punks/2000-2999.csv",
|
12
|
+
# "./datasets/punks/3000-3999.csv",
|
13
|
+
# "./datasets/punks/4000-4999.csv",
|
14
|
+
# "./datasets/punks/5000-5999.csv",
|
15
|
+
# "./datasets/punks/6000-6999.csv",
|
16
|
+
# "./datasets/punks/7000-7999.csv",
|
17
|
+
# "./datasets/punks/8000-8999.csv",
|
18
|
+
# "./datasets/punks/9000-9999.csv"]
|
19
|
+
|
20
|
+
rows = []
|
21
|
+
datasets.each do |dataset|
|
22
|
+
rows += CsvHash.read( dataset )
|
23
|
+
end
|
24
|
+
|
25
|
+
# puts " #{rows.size} rows(s)"
|
26
|
+
#=> 10000 rows(s)
|
27
|
+
|
28
|
+
### wrap in punk struct for easier access
|
29
|
+
punks = []
|
30
|
+
rows.each do |row|
|
31
|
+
id = row['id'].to_i
|
32
|
+
type_q = row['type']
|
33
|
+
count = row['count'].to_i
|
34
|
+
accessories_q = row['accessories'].split( %r{[ ]*/[ ]*} )
|
35
|
+
|
36
|
+
if count != accessories_q.size
|
37
|
+
puts "!! ERROR - punk data assertion failed - expected accessories count #{count}; got #{accessories_q.size}"
|
38
|
+
pp row
|
39
|
+
exit 1
|
40
|
+
end
|
41
|
+
|
42
|
+
type = Metadata::Type.find( type_q )
|
43
|
+
if type.nil?
|
44
|
+
puts "!! ERROR - punk data assertion failed - unknown punk type >#{type_q}<"
|
45
|
+
pp row
|
46
|
+
exit 1
|
47
|
+
end
|
48
|
+
|
49
|
+
accessories = []
|
50
|
+
accessories_q.each do |acc_q|
|
51
|
+
acc = Metadata::Accessory.find( acc_q )
|
52
|
+
if acc.nil?
|
53
|
+
puts "!! ERROR - punk data assertion failed - unknown punk accessory type >#{acc_q}<"
|
54
|
+
pp row
|
55
|
+
exit 1
|
56
|
+
end
|
57
|
+
accessories << acc
|
58
|
+
end
|
59
|
+
|
60
|
+
punks << Metadata.new( id, type, accessories )
|
61
|
+
end
|
62
|
+
punks
|
63
|
+
end
|
64
|
+
end # module Dataset
|
65
|
+
end # module Cryptopunks
|
66
|
+
|
67
|
+
|
@@ -0,0 +1,148 @@
|
|
1
|
+
|
2
|
+
module Cryptopunks
|
3
|
+
### wrap metadata (e.g. punk types, accessories, etc.
|
4
|
+
## in structs for easy/easier access)
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
class Metadata
|
9
|
+
|
10
|
+
## nested class
|
11
|
+
class Type ## todo/check: use alias family or such?
|
12
|
+
attr_reader :name,
|
13
|
+
:limit
|
14
|
+
def initialize( name, limit )
|
15
|
+
@name = name
|
16
|
+
@limit = limit
|
17
|
+
end
|
18
|
+
## def to_s() @name; end
|
19
|
+
|
20
|
+
def inspect
|
21
|
+
%Q{<Type "#{@name}", limit: #{@limit}>}
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
def self.build
|
27
|
+
TYPES.reduce( {} ) do |h, rec|
|
28
|
+
type = Type.new( rec[:name], rec[:limit ] )
|
29
|
+
h[ rec[:name].downcase ] = type
|
30
|
+
h
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.registry
|
35
|
+
## auto-build registry (hash table) lookup (by name)
|
36
|
+
@@types ||= build
|
37
|
+
@@types
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.all() registry.values; end
|
41
|
+
|
42
|
+
def self.find( q ) registry[ q.to_s.downcase ]; end
|
43
|
+
end ## (nested) class Type
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
## nested class
|
48
|
+
class AccessoryType
|
49
|
+
attr_reader :name,
|
50
|
+
:accessories
|
51
|
+
def initialize( name, accessories=[] )
|
52
|
+
@name = name
|
53
|
+
@accessories = accessories
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
def self.build
|
59
|
+
ACCESSORY_TYPES.reduce( {} ) do |h, rec|
|
60
|
+
type = AccessoryType.new( rec[:name] )
|
61
|
+
## add all accessories
|
62
|
+
rec[:accessories].each do |rec_acc|
|
63
|
+
type.accessories << Accessory.new( rec_acc[:name],
|
64
|
+
type,
|
65
|
+
rec_acc[:limit].to_i )
|
66
|
+
end
|
67
|
+
h[ rec[:name].downcase ] = type
|
68
|
+
h
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.registry
|
73
|
+
## auto-build registry (hash table) lookup (by name)
|
74
|
+
@@types ||= build
|
75
|
+
@@types
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.all() registry.values; end
|
79
|
+
|
80
|
+
def self.find( q ) registry[ q.to_s.downcase ]; end
|
81
|
+
end ## (nested) class AccessoryType
|
82
|
+
|
83
|
+
|
84
|
+
## nested class
|
85
|
+
class Accessory
|
86
|
+
|
87
|
+
attr_reader :name,
|
88
|
+
:type,
|
89
|
+
:limit
|
90
|
+
def initialize( name, type, limit )
|
91
|
+
@name = name
|
92
|
+
@type = type
|
93
|
+
@limit = limit
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
def inspect
|
98
|
+
%Q{<Accessory "#{@name}", type: "#{@type.name}", limit: #{@limit}>}
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
|
103
|
+
def self.build
|
104
|
+
AccessoryType.all.reduce( {} ) do |h, type|
|
105
|
+
type.accessories.each do |acc|
|
106
|
+
h[ acc.name.downcase ] = acc
|
107
|
+
end
|
108
|
+
h
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.registry
|
113
|
+
## auto-build registry (hash table) lookup (by name)
|
114
|
+
@@types ||= build
|
115
|
+
@@types
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.all() registry.values; end
|
119
|
+
|
120
|
+
def self.find( q ) registry[ q.to_s.downcase ]; end
|
121
|
+
end ## (nested) class Accessory
|
122
|
+
|
123
|
+
|
124
|
+
|
125
|
+
|
126
|
+
|
127
|
+
|
128
|
+
attr_reader :id,
|
129
|
+
:type,
|
130
|
+
:accessories,
|
131
|
+
:birthday ## todo/check: use minted or such?
|
132
|
+
|
133
|
+
def initialize( id, type, accessories )
|
134
|
+
@id = id
|
135
|
+
@type = type
|
136
|
+
@accessories = accessories
|
137
|
+
@birthday = Date.new( 2017, 6, 23) ## all 10,000 minted on June 23, 2017
|
138
|
+
end
|
139
|
+
|
140
|
+
## convenience helpers for types (5)
|
141
|
+
def alien?() @type.name=='Alien'; end
|
142
|
+
def ape?() @type.name=='Ape'; end
|
143
|
+
def zombie?() @type.name=='Zombie'; end
|
144
|
+
def female?() @type.name=='Female'; end
|
145
|
+
def male?() @type.name=='Male'; end
|
146
|
+
end # class Metadata
|
147
|
+
|
148
|
+
end # module Cryptopunks
|
data/lib/cryptopunks/version.rb
CHANGED
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cryptopunks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gerald Bauer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-04-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: pixelart
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: csvreader
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
@@ -73,10 +73,12 @@ dependencies:
|
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: '3.22'
|
75
75
|
description: cryptopunks - mint your own 24×24 pixel punk images off chain from the
|
76
|
-
True Official Genuine CryptoPunks™ sha256-verified original
|
77
|
-
for bigger sizes
|
76
|
+
True Official Genuine CryptoPunks™ sha256-verified original 10 000 unique character
|
77
|
+
collection; incl. 2x/4x/8x zoom for bigger sizes
|
78
78
|
email: wwwmake@googlegroups.com
|
79
|
-
executables:
|
79
|
+
executables:
|
80
|
+
- cryptopunk
|
81
|
+
- punk
|
80
82
|
extensions: []
|
81
83
|
extra_rdoc_files:
|
82
84
|
- CHANGELOG.md
|
@@ -87,9 +89,15 @@ files:
|
|
87
89
|
- Manifest.txt
|
88
90
|
- README.md
|
89
91
|
- Rakefile
|
92
|
+
- bin/cryptopunk
|
93
|
+
- bin/punk
|
90
94
|
- lib/cryptopunks.rb
|
95
|
+
- lib/cryptopunks/attributes.rb
|
96
|
+
- lib/cryptopunks/composite.rb
|
97
|
+
- lib/cryptopunks/dataset.rb
|
98
|
+
- lib/cryptopunks/structs.rb
|
91
99
|
- lib/cryptopunks/version.rb
|
92
|
-
homepage: https://github.com/
|
100
|
+
homepage: https://github.com/cryptopunksnotdead/cryptopunks
|
93
101
|
licenses:
|
94
102
|
- Public Domain
|
95
103
|
metadata: {}
|
@@ -114,6 +122,6 @@ rubygems_version: 3.1.4
|
|
114
122
|
signing_key:
|
115
123
|
specification_version: 4
|
116
124
|
summary: cryptopunks - mint your own 24×24 pixel punk images off chain from the True
|
117
|
-
Official Genuine CryptoPunks™ sha256-verified original
|
118
|
-
bigger sizes
|
125
|
+
Official Genuine CryptoPunks™ sha256-verified original 10 000 unique character collection;
|
126
|
+
incl. 2x/4x/8x zoom for bigger sizes
|
119
127
|
test_files: []
|