basic image thumbnails

This commit is contained in:
Emi Matchu 2012-07-16 16:47:28 -04:00
parent 7c015e2d88
commit cf2546d832
6 changed files with 65 additions and 16 deletions

View file

@ -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)

View file

@ -0,0 +1,8 @@
class OutfitImageUpdate
@queue = :outfit_image_updates
def self.perform(id)
Outfit.find(id).write_image!
end
end

View file

@ -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']

View file

@ -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

View file

@ -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
View file

@ -0,0 +1,2 @@
*
!.gitignore