Skip to content

Instantly share code, notes, and snippets.

@jimhj
Created July 11, 2012 08:28
Show Gist options
  • Save jimhj/3089015 to your computer and use it in GitHub Desktop.
Save jimhj/3089015 to your computer and use it in GitHub Desktop.
Use Mini_Magick to crop animated gif images.
# coding: utf-8
module SimpleUpload
class Base
class << self
def max_size
10485760 #(10M)
end
def extension_white_list
%w(jpg jpeg png gif)
end
def customizable_storage?
AppConfig.get(:enable_image_storage_parse)
end
def location_to_store
return nil unless customizable_storage?
AppConfig.get(:location_to_store_uploaded_assets)
end
# Create a dir like '/23/33'.
def rand_dir
File.join('%02d' % rand(99), '%02d' % rand(99))
end
def filename
Digest::MD5.hexdigest([Time.now.to_i.to_s, rand.to_s].join('-'))
end
def white_background_img
File.join(Rails.root, 'public', 'white_background.jpg')
end
# Uncomment this to add watermark
# def watermark
# end
def versions
{
:l => '600x900>',
:m => '200x300>',
:c => '80x80',
:s => '50x50'
}
end
end
end #Base End
end
require 'simple_upload'
# coding: utf-8
require 'mini_magick'
require 'open-uri'
# TODO: Crop image.
module SimpleUpload
class Upload < Base
attr_accessor :status, :dfs_path, :errors, :image
def initialize(file, product_dir)
@status, @dfs_path, @errors = false, nil, []
@image = nil
if file.nil?
@errors << '请选择一张图片上传'
else
if file.is_a? ActionDispatch::Http::UploadedFile
file_path = file.tempfile.path
elsif file.is_a? Tempfile
file_path = file.path
elsif file.is_a? String
# TODO: refine upload a image from a remote url.
if File.exist?(file) || file.start_with?('http://')
file_path = file
end
# file_path = file
# file_path = 'http://' + file if !file.start_with?('http://')
end
begin
@image = MiniMagick::Image.open(file_path)
@errors << '不支持这种格式的图片' if !self.class.extension_white_list.include?(@image[:format].downcase)
@errors << '图片超出了最大限制' if @image[:size].to_i > self.class.max_size
rescue => e
@errors << '不支持的文件'
end
end
end
class << self
def extension_white_list; super end
def versions; super end
def max_size; super end
##
# Uploads the Image and returns an object.
# Paramters:
# [file (Tempfile or A remote url)]
# [product_dir (string)]
#
# Usage:
# upload = SimpleUpload::Upload.process(file_or_url, 'p')
# if upload.status
# dfs = upload.dfs_path
# else
# errors = upload.errors
# end
##
def process(file, product_dir = 'p')
upload = self.new(file, product_dir)
if upload.errors.length == 0
@product_dir, @rand_dir = product_dir, rand_dir
filename, extension = self.filename, upload.image[:format].downcase
orig_target_dir = File.join(store_dir, "o_#{filename}.#{extension}")
begin
FileUtils.mkdir_p(store_dir)
upload.image.write(orig_target_dir)
self.gen_thumbnails(orig_target_dir, "#{filename}.#{extension}")
upload.status = true
upload.dfs_path = [filename, extension, 0, 0, @product_dir, 0, 0, @rand_dir.split('/')].join('|')
rescue => e
p e.inspect
upload.errors = ['上传中出错了,请重试']
end
end
return upload
end
# TODO: Crop image from remote url.
# Dfs Path Rule: 481324679f9b4aa85b412a59d1da3127|jpeg|0|0|p|0|0|52|05
def crop(file, crop_position, product_dir = 'a')
file_path = get_absolute_dir(file)
return nil unless File.exist?(file_path)
return nil if !crop_position.is_a?(Array) && crop_position.length == 4
x, y, w, h = crop_position
image = MiniMagick::Image.open(file_path)
if image.mime_type == 'image/gif'
image.crop("#{w}x#{h}+#{x}+#{y}!")
image.coalesce(file_path, file_path)
else
image.crop("#{w}x#{h}+#{x}+#{y}")
end
image.write(file_path)
upload = self.process(file_path, product_dir)
end
def composite_white_background(dfs_path, product_dir = 'a')
file_path = get_absolute_dir(dfs_path)
image = MiniMagick::Image.open(file_path)
if image.mime_type == 'image/gif'
image.run_command("convert #{white_background_img} null: #{file_path} -gravity Center -layers Composite #{file_path}")
else
composite_img = MiniMagick::Image.open(white_background_img).clone
composite_img.composite(image) do |img|
img.gravity "Center"
end.write(file_path)
end
self.process(file_path, product_dir)
end
def resize_to_limit(image, size)
size << '>' unless size.end_with?('>')
image.resize size
end
def resize_to_fill(image, size)
cols, rows = image[:dimensions]
width, height = size.split('x').map{ |length| length.to_i }
image.combine_options do |cmd|
if width != cols || height != rows
scale = [width / cols.to_f, height / rows.to_f].max
cols = (scale * (cols + 0.5)).round
rows = (scale * (rows + 0.5)).round
cmd.resize "#{cols}x#{rows}"
end
cmd.gravity 'Center'
cmd.background "rgba(255,255,255,0.0)"
cmd.extent "#{width}x#{height}" if cols != width || rows != height
end
end
# def resize_crop(image, size)
# p 111111
# w, h = image[:width], image[:height]
# shaved_off = ((w - h) / 2).round
# p w, h
# x = image.shave "#{shaved_off}x0"
# p x
# end
# Make thumbnails from original image or a remore url.
def gen_thumbnails(original_file, fullfilename)
orig_img = MiniMagick::Image.open(original_file)
self.versions.each do |style, size|
case style
when :l, :m
self.resize_to_limit(orig_img, size)
else
self.resize_to_fill(orig_img, size)
end
orig_img.resize(size)
orig_img.write File.join(store_dir, "#{style}_#{fullfilename}")
end
end
private
def get_absolute_dir(dfs_path, style = 'l')
dir_arr = (dfs_path || '').split('|')
return nil if dir_arr.length == 0
rand_dir, dir = File.join(dir_arr[-2], dir_arr[-1]), dir_arr[4]
root_dir = customizable_storage? ? location_to_store : File.join(Rails.root, 'public')
file_path = File.join(root_dir, dir, rand_dir, "#{style}_#{dir_arr[0]}.#{dir_arr[1]}")
end
def store_dir
if customizable_storage?
File.join(location_to_store, @product_dir, @rand_dir)
else
File.join(Rails.root, 'public', @product_dir, @rand_dir)
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment