Class: CryptopunksGui::Model::Image

Inherits:
Object
  • Object
show all
Defined in:
app/model/image.rb

Constant Summary collapse

PALETTES =
['Standard'] + (Palette8bit.constants).map(&:name).map {|palette| palette.split('_').map(&:capitalize).join(' ')}.reject { |palette| palette.include?(' ') }.sort
STYLES =
['Normal', 'Led', 'Sketch']
OUTPUT_LOCATION_DEFAULT =
File.join(Dir.home, 'cryptopunks')
CONFIG_FILE =
File.join(OUTPUT_LOCATION_DEFAULT, 'cryptopunks.yml')
COLLECTIONS_YAML_PATH =
File.join(OUTPUT_LOCATION_DEFAULT, 'cryptopunks-collections.yml')
COLLECTIONS_YAML_URL =
'https://raw.githubusercontent.com/cryptopunksnotdead/cryptopunks-gui/master/cryptopunks-collections.yml'
COLLECTIONS_YAML_REPO_PATH =
File.expand_path('../../cryptopunks-collections.yml', __dir__)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeImage

Returns a new instance of Image.



15
16
17
18
19
20
21
22
# File 'app/model/image.rb', line 15

def initialize
  initialize_output_location
  initialize_collections_map
  initialize_collection
  load_config
  initialize_defaults
  observe_image_attribute_changes
end

Instance Attribute Details

#collectionObject

Returns the value of attribute collection.



12
13
14
# File 'app/model/image.rb', line 12

def collection
  @collection
end

#collection_sizeObject

Returns the value of attribute collection_size.



12
13
14
# File 'app/model/image.rb', line 12

def collection_size
  @collection_size
end

#collections_mapObject

Returns the value of attribute collections_map.



12
13
14
# File 'app/model/image.rb', line 12

def collections_map
  @collections_map
end

#configObject

Returns the value of attribute config.



12
13
14
# File 'app/model/image.rb', line 12

def config
  @config
end

#flipObject

Returns the value of attribute flip.



12
13
14
# File 'app/model/image.rb', line 12

def flip
  @flip
end

#image_indexObject

Returns the value of attribute image_index.



12
13
14
# File 'app/model/image.rb', line 12

def image_index
  @image_index
end

#image_locationObject

Returns the value of attribute image_location.



12
13
14
# File 'app/model/image.rb', line 12

def image_location
  @image_location
end

#imagesObject

Returns the value of attribute images.



12
13
14
# File 'app/model/image.rb', line 12

def images
  @images
end

#led_round_cornerObject

Returns the value of attribute led_round_corner.



12
13
14
# File 'app/model/image.rb', line 12

def led_round_corner
  @led_round_corner
end

#led_spacingObject

Returns the value of attribute led_spacing.



12
13
14
# File 'app/model/image.rb', line 12

def led_spacing
  @led_spacing
end

#mirrorObject

Returns the value of attribute mirror.



12
13
14
# File 'app/model/image.rb', line 12

def mirror
  @mirror
end

#output_locationObject

Returns the value of attribute output_location.



12
13
14
# File 'app/model/image.rb', line 12

def output_location
  @output_location
end

#paletteObject

Returns the value of attribute palette.



12
13
14
# File 'app/model/image.rb', line 12

def palette
  @palette
end

#sketch_lineObject

Returns the value of attribute sketch_line.



12
13
14
# File 'app/model/image.rb', line 12

def sketch_line
  @sketch_line
end

#styleObject

Returns the value of attribute style.



12
13
14
# File 'app/model/image.rb', line 12

def style
  @style
end

#zoomObject

Returns the value of attribute zoom.



12
13
14
# File 'app/model/image.rb', line 12

def zoom
  @zoom
end

Instance Method Details

#change_output_location(new_output_location) ⇒ Object



172
173
174
175
176
177
# File 'app/model/image.rb', line 172

def change_output_location(new_output_location)
  @output_location = new_output_location
  @config[:output_location] = @output_location
  save_config
  generate_image
end

#collection_optionsObject



24
25
26
# File 'app/model/image.rb', line 24

def collection_options
  @collections_map.keys.select {|collection_name| @collections_map[collection_name][:enabled]}
end

#generate_imageObject



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'app/model/image.rb', line 140

def generate_image
  initialize_collection
  return if @image_index.to_i >= @images[@collection].size
  new_image_location = File.join(@output_location, "#{@collection.gsub(' ', '').downcase}-#{@image_index}#{"x#{@zoom}" if @zoom.to_i > 1}#{"-#{@palette.underscore}" if @palette != PALETTES.first}#{"-#{@style.underscore}" if @style != STYLES.first}#{"-spacing#{@led_spacing.to_i}" if @style == 'Led'}#{'-round-corner' if @style == 'Led' && @led_round_corner}#{"-line#{@sketch_line.to_i}" if @style == 'Sketch'}#{'-mirror' if @mirror}#{'-flip' if @flip}.png")
  puts "Writing punk image to #{new_image_location}"
  selected_punk = @images[@collection][@image_index.to_i]
  selected_punk = selected_punk.change_palette8bit(Palette8bit.const_get(@palette.gsub(' ', '_').upcase.to_sym)) if @palette != PALETTES.first
  @original_zoom = @zoom
  if @previous_collection && @collection != @previous_collection && @collections_map[@collection][:width] != @collections_map[@previous_collection][:width]
    @zoom = @collections_map[@collection][:default_zoom]
  end
  if @style != STYLES.first
    style_options = {}
    if @style == 'Led'
      style_options[:spacing] = @led_spacing.to_i
      style_options[:round_corner] = @led_round_corner
    end
    if @style == 'Sketch'
      style_options[:line] = @sketch_line.to_i
    end
    selected_punk = selected_punk.send(@style.underscore, @zoom.to_i, **style_options)
  end
  selected_punk = selected_punk.mirror if @mirror
  selected_punk = selected_punk.flip if @flip
  selected_punk = selected_punk.zoom(@zoom.to_i) if @style == STYLES.first
  selected_punk.save(new_image_location)
  self.image_location = new_image_location
  notify_observers(:zoom) if @zoom != @original_zoom
  @previous_style = @style
  @previous_collection = @collection
end

#initialize_collectionObject



89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'app/model/image.rb', line 89

def initialize_collection
  return if @collection && @collection == @last_collection
  @collection ||= @collections_map.keys.first
  url = @collections_map[@collection][:url]
  width = @collections_map[@collection][:width]
  height = @collections_map[@collection][:height]
  @image_file = File.join(OUTPUT_LOCATION_DEFAULT, File.basename(url))
  File.write(@image_file, Net::HTTP.get(URI(url))) unless File.exist?(@image_file)
  @images ||= {}
  @images[@collection] ||= Punks::Image::Composite.read(@image_file, width: width, height: height)
  @last_collection = @collection
  self.image_index = 0
end

#initialize_collections_map(reset: false) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'app/model/image.rb', line 41

def initialize_collections_map(reset: false)
  FileUtils.touch(COLLECTIONS_YAML_PATH)
  @collections_map = reset ? {} : (YAML.load(File.read(COLLECTIONS_YAML_PATH)) || {})
  new_collections_map = {}
  begin
    http_response = Net::HTTP.get_response(URI(COLLECTIONS_YAML_URL))
    if http_response.is_a?(Net::HTTPSuccess)
      new_collections_map = YAML.load(http_response.body)
    else
      raise "code: #{http_response.code} message: #{http_response.message}"
    end
  rescue StandardError, SocketError => e
    puts "Failed to utilize collection YAML from: #{COLLECTIONS_YAML_URL}"
    puts e.full_message
    puts "Utilizing local collection YAML instead: #{COLLECTIONS_YAML_REPO_PATH}"
    new_collections_map = YAML.load(File.read(COLLECTIONS_YAML_REPO_PATH)) rescue {}
  end
  @collections_map_observers ||= {}
  new_collections_map.each do |collection_name, collection_options|
    @collections_map[collection_name] ||= {}
    original_collections_map_for_collection = @collections_map[collection_name]
    @collections_map[collection_name] = @collections_map[collection_name]
    @collections_map[collection_name].reverse_merge!(collection_options)
    @collections_map[collection_name][:enabled] = true unless @collections_map[collection_name].has_key?(:enabled)
    @collections_map_observers[collection_name] ||= Glimmer::DataBinding::Observer.proc { |value, key|
      if key == :enabled
        self.collection = @collections_map.find { |name, options| options[:enabled] }.first if key == :enabled && value == false && @collection == collection_name
        notify_observers(:collection_options)
      end
      save_collections_map
    }.tap {|o| o.observe(original_collections_map_for_collection)}
  end
  @collections_map_observer ||= Glimmer::DataBinding::Observer.proc { |collection_options, collection_name|
    if collection_options.nil?
      self.collection = @collections_map.find { |name, options| options[:enabled] }.first if @collection == collection_name
      self.collection = collection_name if @collections_map.select { |name, options| options[:enabled] }.count == 0
    end
    notify_observers(:collection_options)
    save_collections_map
  }.tap {|o| o.observe(@collections_map)}
  save_collections_map
end

#initialize_defaultsObject



114
115
116
117
118
119
120
121
122
123
124
# File 'app/model/image.rb', line 114

def initialize_defaults
  @collection = @collections_map.keys.first
  @zoom = 12
  @palette = PALETTES.first
  @style = STYLES.first
  @led_spacing = 2
  @led_round_corner = false
  @sketch_line = 1
  @mirror = false
  @flip = false
end

#initialize_output_locationObject



36
37
38
39
# File 'app/model/image.rb', line 36

def initialize_output_location
  @output_location = OUTPUT_LOCATION_DEFAULT
  FileUtils.mkdir_p(@output_location)
end

#load_configObject



103
104
105
106
107
108
# File 'app/model/image.rb', line 103

def load_config
  FileUtils.touch(CONFIG_FILE)
  @config = YAML.load(File.read(CONFIG_FILE)) || {}
  @output_location = @config[:output_location]
  @config[:output_location] = @output_location = OUTPUT_LOCATION_DEFAULT if @output_location.nil?
end

#observe_image_attribute_changesObject



126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'app/model/image.rb', line 126

def observe_image_attribute_changes
  observer = Glimmer::DataBinding::Observer.proc { generate_image }
  observer.observe(self, :collection)
  observer.observe(self, :image_index)
  observer.observe(self, :zoom)
  observer.observe(self, :palette)
  observer.observe(self, :style)
  observer.observe(self, :led_spacing)
  observer.observe(self, :led_round_corner)
  observer.observe(self, :sketch_line)
  observer.observe(self, :mirror)
  observer.observe(self, :flip)
end

#palette_optionsObject



28
29
30
# File 'app/model/image.rb', line 28

def palette_options
  PALETTES
end

#reset_output_locationObject



179
180
181
182
183
184
# File 'app/model/image.rb', line 179

def reset_output_location
  @output_location = OUTPUT_LOCATION_DEFAULT
  @config[:output_location] = @output_location
  save_config
  generate_image
end

#save_collections_mapObject



84
85
86
87
# File 'app/model/image.rb', line 84

def save_collections_map
  normalized_collections_map = Hash[@collections_map.map {|k,v| [k, v.to_h]}]
  File.write(COLLECTIONS_YAML_PATH, YAML.dump(normalized_collections_map))
end

#save_configObject



110
111
112
# File 'app/model/image.rb', line 110

def save_config
  File.write(CONFIG_FILE, YAML.dump(@config))
end

#style_optionsObject



32
33
34
# File 'app/model/image.rb', line 32

def style_options
  STYLES
end