cryptopunks 0.0.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punks-zoom.png)
|
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
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-0000.png)
|
70
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-2890.png)
|
71
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-8219.png)
|
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
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-0000x2.png)
|
100
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-2890x2.png)
|
101
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-8219x2.png)
|
102
|
+
|
103
|
+
And x4:
|
104
|
+
|
105
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-0000x4.png)
|
106
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-2890x4.png)
|
107
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-8219x4.png)
|
108
|
+
|
109
|
+
|
110
|
+
And x8:
|
111
|
+
|
112
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-0000x8.png)
|
113
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-2890x8.png)
|
114
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-8219x8.png)
|
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
|
+
![](https://github.com/cryptopunksnotdead/awesome-cryptopunks-bubble/raw/master/i/more-punks-1.png)
|
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
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-10000.png)
|
162
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-10018.png)
|
163
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-10040.png)
|
164
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-10088.png)
|
165
|
+
|
166
|
+
|
167
|
+
And 4x:
|
168
|
+
|
169
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-10000x4.png)
|
170
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-10018x4.png)
|
171
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-10040x4.png)
|
172
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-10088x4.png)
|
173
|
+
|
174
|
+
|
175
|
+
|
176
|
+
|
177
|
+
Let's try the second pack - that is, punks 100 to 199 in the series.
|
178
|
+
|
179
|
+
|
180
|
+
![](https://github.com/cryptopunksnotdead/awesome-cryptopunks-bubble/raw/master/i/more-punks-2.png)
|
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
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-10100.png)
|
207
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-10179.png)
|
208
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-10180.png)
|
209
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-10190.png)
|
210
|
+
|
211
|
+
|
212
|
+
And 4x:
|
213
|
+
|
214
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-10100x4.png)
|
215
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-10179x4.png)
|
216
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-10180x4.png)
|
217
|
+
![](https://github.com/cryptopunksnotdead/cryptopunks/raw/master/cryptopunks/i/punk-10190x4.png)
|
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: []
|