2013-02-22 20:47:26 +08:00
|
|
|
#
|
2013-04-13 22:31:20 +08:00
|
|
|
# This class is used to download and optimize images.
|
2013-02-22 20:47:26 +08:00
|
|
|
#
|
2013-04-13 22:31:20 +08:00
|
|
|
|
|
|
|
require 'image_sorcery'
|
|
|
|
require 'digest/sha1'
|
|
|
|
require 'open-uri'
|
2013-02-22 07:56:59 +08:00
|
|
|
|
|
|
|
class ImageOptimizer
|
2013-04-13 22:31:20 +08:00
|
|
|
attr_accessor :url
|
|
|
|
|
2013-02-26 00:42:20 +08:00
|
|
|
# url is a url of an image ex:
|
2013-02-22 20:47:26 +08:00
|
|
|
# 'http://site.com/image.png'
|
|
|
|
# '/uploads/site/image.png'
|
2013-04-13 22:31:20 +08:00
|
|
|
def initialize(url)
|
|
|
|
@url = url
|
|
|
|
# make sure directories exists
|
|
|
|
FileUtils.mkdir_p downloads_dir
|
|
|
|
FileUtils.mkdir_p optimized_dir
|
2013-02-22 20:47:26 +08:00
|
|
|
end
|
2013-02-26 00:42:20 +08:00
|
|
|
|
|
|
|
# return the path of an optimized image,
|
|
|
|
# if already cached return cached, else download and cache
|
|
|
|
# at the original size.
|
2013-02-22 20:47:26 +08:00
|
|
|
# if size is specified return a resized image
|
2013-02-26 00:42:20 +08:00
|
|
|
# if height or width are nil maintain aspect ratio
|
|
|
|
#
|
|
|
|
# Optimised image is the "most efficient" storage for an image
|
2013-02-22 20:47:26 +08:00
|
|
|
# at the basic level it runs through image_optim https://github.com/toy/image_optim
|
2013-02-26 00:42:20 +08:00
|
|
|
# it also has a failsafe that converts jpg to png or the opposite. if jpg size is 1.5*
|
|
|
|
# as efficient as png it flips formats.
|
2013-04-13 22:31:20 +08:00
|
|
|
def optimized_image_url (width = nil, height = nil)
|
|
|
|
begin
|
|
|
|
unless has_been_uploaded?
|
|
|
|
return @url unless SiteSetting.crawl_images?
|
|
|
|
# download the file if it hasn't been cached yet
|
|
|
|
download! unless File.exists?(cached_path)
|
|
|
|
end
|
|
|
|
|
|
|
|
# resize the image using Image Magick
|
|
|
|
result = ImageSorcery.new(cached_path).convert(optimized_path, resize: "#{width}x#{height}")
|
|
|
|
return optimized_url if result
|
|
|
|
@url
|
|
|
|
rescue
|
|
|
|
@url
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def public_dir
|
|
|
|
@public_dir ||= "#{Rails.root}/public"
|
|
|
|
end
|
|
|
|
|
|
|
|
def downloads_dir
|
|
|
|
@downloads_dir ||= "#{public_dir}/downloads/#{RailsMultisite::ConnectionManagement.current_db}"
|
|
|
|
end
|
|
|
|
|
|
|
|
def optimized_dir
|
|
|
|
@optimized_dir ||= "#{public_dir}/images/#{RailsMultisite::ConnectionManagement.current_db}"
|
|
|
|
end
|
|
|
|
|
|
|
|
def has_been_uploaded?
|
|
|
|
@url.start_with?(Discourse.base_url_no_prefix)
|
|
|
|
end
|
|
|
|
|
|
|
|
def cached_path
|
|
|
|
@cached_path ||= if has_been_uploaded?
|
|
|
|
"#{public_dir}#{@url[Discourse.base_url_no_prefix.length..-1]}"
|
|
|
|
else
|
|
|
|
"#{downloads_dir}/#{file_name(@url)}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def optimized_path
|
|
|
|
@optimized_path ||= "#{optimized_dir}/#{file_name(cached_path)}"
|
|
|
|
end
|
|
|
|
|
|
|
|
def file_name (uri)
|
|
|
|
image_info = FastImage.new(uri)
|
|
|
|
name = Digest::SHA1.hexdigest(uri)[0,16]
|
|
|
|
name << ".#{image_info.type}"
|
|
|
|
name
|
|
|
|
end
|
|
|
|
|
|
|
|
def download!
|
|
|
|
File.open(cached_path, "wb") do |f|
|
|
|
|
f.write open(@url, "rb", read_timeout: 20).read
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def optimized_url
|
2013-04-19 06:19:08 +08:00
|
|
|
@optimized_url ||= Discourse.base_url_no_prefix + "/images/#{RailsMultisite::ConnectionManagement.current_db}/#{file_name(cached_path)}"
|
2013-02-22 07:56:59 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
end
|