basic image thumbnails
This commit is contained in:
parent
7c015e2d88
commit
cf2546d832
6 changed files with 65 additions and 16 deletions
|
@ -14,6 +14,8 @@ class Outfit < ActiveRecord::Base
|
|||
scope :wardrobe_order, order('starred DESC', :name)
|
||||
|
||||
mount_uploader :image, OutfitImageUploader
|
||||
|
||||
after_commit :enqueue_image!
|
||||
|
||||
def as_json(more_options={})
|
||||
serializable_hash :only => [:id, :name, :pet_state_id, :starred],
|
||||
|
@ -68,23 +70,35 @@ class Outfit < ActiveRecord::Base
|
|||
end
|
||||
|
||||
# Returns the array of SwfAssets representing each layer of the output image,
|
||||
# ordered from bottom to top.
|
||||
def layered_assets
|
||||
visible_assets.sort { |a, b| a.zone.depth <=> b.zone.depth }
|
||||
# ordered from bottom to top. Careful: this method is memoized, so if the
|
||||
# image layers change after its first call we'll get bad results.
|
||||
def image_layers
|
||||
@image_layers ||= visible_assets_with_images.sort { |a, b| a.zone.depth <=> b.zone.depth }
|
||||
end
|
||||
|
||||
# Creates and writes the thumbnail images for this outfit. (Writes to file in
|
||||
# development, S3 in production.) Runs #save! on the record, so any other
|
||||
# changes will also be saved.
|
||||
# Creates and writes the thumbnail images for this outfit iff the new image
|
||||
# would be different than the current one. (Writes to file in development,
|
||||
# S3 in production.) If the image is updated, updates the image layers hash
|
||||
# and runs #save! on the record, so any other changes will also be saved.
|
||||
def write_image!
|
||||
Tempfile.open(['outfit_image', '.png']) do |image|
|
||||
create_image! image
|
||||
self.image = image
|
||||
save!
|
||||
if image_layers_dirty?
|
||||
Tempfile.open(['outfit_image', '.png']) do |image|
|
||||
create_image! image
|
||||
self.image_layers_hash = generate_image_layers_hash
|
||||
self.image = image
|
||||
save!
|
||||
end
|
||||
end
|
||||
|
||||
self.image
|
||||
end
|
||||
|
||||
# Enqueue an image write iff the new image would be different than the
|
||||
# current one.
|
||||
def enqueue_image!
|
||||
Resque.enqueue(OutfitImageUpdate, id) if image_layers_dirty?
|
||||
end
|
||||
|
||||
def s3_key(size)
|
||||
URI.encode("#{id}/#{size.join 'x'}.png")
|
||||
end
|
||||
|
@ -108,13 +122,13 @@ class Outfit < ActiveRecord::Base
|
|||
# Creates a 600x600 PNG image of this outfit, writing to the given output
|
||||
# file.
|
||||
def create_image!(output)
|
||||
layers = self.layered_assets
|
||||
base_layer = layers.shift
|
||||
base_layer = image_layers.first
|
||||
above_layers = image_layers[1..-1]
|
||||
write_temp_swf_asset_image! base_layer, output
|
||||
output.close
|
||||
|
||||
Tempfile.open(['outfit_overlay', '.png']) do |overlay|
|
||||
layers.each do |layer|
|
||||
above_layers.each do |layer|
|
||||
overlay.open
|
||||
write_temp_swf_asset_image! layer, overlay
|
||||
overlay.close
|
||||
|
@ -151,6 +165,21 @@ class Outfit < ActiveRecord::Base
|
|||
all_assets.select { |a| (1 << (a.zone_id - 1)) & restricted_zones_mask == 0 }
|
||||
end
|
||||
|
||||
def visible_assets_with_images
|
||||
visible_assets.select(&:has_image?)
|
||||
end
|
||||
|
||||
# Generate 8-char hex digest representing visible image layers for this outfit.
|
||||
# Hash function should be decently collision-resistant.
|
||||
def generate_image_layers_hash
|
||||
@generated_image_layers_hash ||=
|
||||
Digest::MD5.hexdigest(image_layers.map(&:id).join(',')).first(8)
|
||||
end
|
||||
|
||||
def image_layers_dirty?
|
||||
generate_image_layers_hash != self.image_layers_hash
|
||||
end
|
||||
|
||||
IMAGE_BASE_SIZE = [600, 600]
|
||||
def write_temp_swf_asset_image!(swf_asset, file)
|
||||
key = swf_asset.s3_key(IMAGE_BASE_SIZE)
|
||||
|
|
8
app/models/outfit_image_update.rb
Normal file
8
app/models/outfit_image_update.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
class OutfitImageUpdate
|
||||
@queue = :outfit_image_updates
|
||||
|
||||
def self.perform(id)
|
||||
Outfit.find(id).write_image!
|
||||
end
|
||||
end
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
# this to use S3 on all environments for those images only.)
|
||||
|
||||
CarrierWave.configure do |config|
|
||||
if Rails.env.production? || true # REMOVE
|
||||
if Rails.env.production?
|
||||
s3_config = YAML.load_file Rails.root.join('config', 'aws_s3.yml')
|
||||
access_key_id = s3_config['access_key_id']
|
||||
secret_access_key = s3_config['secret_access_key']
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
class AddImageLayersHashToOutfit < ActiveRecord::Migration
|
||||
def self.up
|
||||
add_column :outfits, :image_layers_hash, :string, :length => 8
|
||||
end
|
||||
|
||||
def self.down
|
||||
remove_column :outfits, :image_layers_hash
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20120521164652) do
|
||||
ActiveRecord::Schema.define(:version => 20120716193946) do
|
||||
|
||||
create_table "auth_servers", :force => true do |t|
|
||||
t.string "short_name", :limit => 10, :null => false
|
||||
|
@ -116,8 +116,9 @@ ActiveRecord::Schema.define(:version => 20120521164652) do
|
|||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.string "name"
|
||||
t.boolean "starred", :default => false, :null => false
|
||||
t.boolean "starred", :default => false, :null => false
|
||||
t.string "image"
|
||||
t.string "image_layers_hash"
|
||||
end
|
||||
|
||||
add_index "outfits", ["pet_state_id"], :name => "index_outfits_on_pet_state_id"
|
||||
|
|
2
public/outfits/.gitignore
vendored
Normal file
2
public/outfits/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
Loading…
Reference in a new issue