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)
|
scope :wardrobe_order, order('starred DESC', :name)
|
||||||
|
|
||||||
mount_uploader :image, OutfitImageUploader
|
mount_uploader :image, OutfitImageUploader
|
||||||
|
|
||||||
|
after_commit :enqueue_image!
|
||||||
|
|
||||||
def as_json(more_options={})
|
def as_json(more_options={})
|
||||||
serializable_hash :only => [:id, :name, :pet_state_id, :starred],
|
serializable_hash :only => [:id, :name, :pet_state_id, :starred],
|
||||||
|
@ -68,23 +70,35 @@ class Outfit < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the array of SwfAssets representing each layer of the output image,
|
# Returns the array of SwfAssets representing each layer of the output image,
|
||||||
# ordered from bottom to top.
|
# ordered from bottom to top. Careful: this method is memoized, so if the
|
||||||
def layered_assets
|
# image layers change after its first call we'll get bad results.
|
||||||
visible_assets.sort { |a, b| a.zone.depth <=> b.zone.depth }
|
def image_layers
|
||||||
|
@image_layers ||= visible_assets_with_images.sort { |a, b| a.zone.depth <=> b.zone.depth }
|
||||||
end
|
end
|
||||||
|
|
||||||
# Creates and writes the thumbnail images for this outfit. (Writes to file in
|
# Creates and writes the thumbnail images for this outfit iff the new image
|
||||||
# development, S3 in production.) Runs #save! on the record, so any other
|
# would be different than the current one. (Writes to file in development,
|
||||||
# changes will also be saved.
|
# 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!
|
def write_image!
|
||||||
Tempfile.open(['outfit_image', '.png']) do |image|
|
if image_layers_dirty?
|
||||||
create_image! image
|
Tempfile.open(['outfit_image', '.png']) do |image|
|
||||||
self.image = image
|
create_image! image
|
||||||
save!
|
self.image_layers_hash = generate_image_layers_hash
|
||||||
|
self.image = image
|
||||||
|
save!
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self.image
|
self.image
|
||||||
end
|
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)
|
def s3_key(size)
|
||||||
URI.encode("#{id}/#{size.join 'x'}.png")
|
URI.encode("#{id}/#{size.join 'x'}.png")
|
||||||
end
|
end
|
||||||
|
@ -108,13 +122,13 @@ class Outfit < ActiveRecord::Base
|
||||||
# Creates a 600x600 PNG image of this outfit, writing to the given output
|
# Creates a 600x600 PNG image of this outfit, writing to the given output
|
||||||
# file.
|
# file.
|
||||||
def create_image!(output)
|
def create_image!(output)
|
||||||
layers = self.layered_assets
|
base_layer = image_layers.first
|
||||||
base_layer = layers.shift
|
above_layers = image_layers[1..-1]
|
||||||
write_temp_swf_asset_image! base_layer, output
|
write_temp_swf_asset_image! base_layer, output
|
||||||
output.close
|
output.close
|
||||||
|
|
||||||
Tempfile.open(['outfit_overlay', '.png']) do |overlay|
|
Tempfile.open(['outfit_overlay', '.png']) do |overlay|
|
||||||
layers.each do |layer|
|
above_layers.each do |layer|
|
||||||
overlay.open
|
overlay.open
|
||||||
write_temp_swf_asset_image! layer, overlay
|
write_temp_swf_asset_image! layer, overlay
|
||||||
overlay.close
|
overlay.close
|
||||||
|
@ -151,6 +165,21 @@ class Outfit < ActiveRecord::Base
|
||||||
all_assets.select { |a| (1 << (a.zone_id - 1)) & restricted_zones_mask == 0 }
|
all_assets.select { |a| (1 << (a.zone_id - 1)) & restricted_zones_mask == 0 }
|
||||||
end
|
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]
|
IMAGE_BASE_SIZE = [600, 600]
|
||||||
def write_temp_swf_asset_image!(swf_asset, file)
|
def write_temp_swf_asset_image!(swf_asset, file)
|
||||||
key = swf_asset.s3_key(IMAGE_BASE_SIZE)
|
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.)
|
# this to use S3 on all environments for those images only.)
|
||||||
|
|
||||||
CarrierWave.configure do |config|
|
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')
|
s3_config = YAML.load_file Rails.root.join('config', 'aws_s3.yml')
|
||||||
access_key_id = s3_config['access_key_id']
|
access_key_id = s3_config['access_key_id']
|
||||||
secret_access_key = s3_config['secret_access_key']
|
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.
|
# 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|
|
create_table "auth_servers", :force => true do |t|
|
||||||
t.string "short_name", :limit => 10, :null => false
|
t.string "short_name", :limit => 10, :null => false
|
||||||
|
@ -116,8 +116,9 @@ ActiveRecord::Schema.define(:version => 20120521164652) do
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.string "name"
|
t.string "name"
|
||||||
t.boolean "starred", :default => false, :null => false
|
t.boolean "starred", :default => false, :null => false
|
||||||
t.string "image"
|
t.string "image"
|
||||||
|
t.string "image_layers_hash"
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "outfits", ["pet_state_id"], :name => "index_outfits_on_pet_state_id"
|
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