Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions enbake_attach.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Gem::Specification.new do |s|
s.name = 'enbake_attach'
s.version = '0.0.1'
s.date = '2015-09-17'
s.summary = "Enbake Attach"
s.description = "Enbake Attach is a Gem for handling attachments in Rails. Its a whoopie doo version of attachment_fu"
s.authors = ["Ishwinder Singh"]
s.email = 'singh.ishwinder@gmail.com'
s.files = `git ls-files`.split($/)
s.require_paths = ["lib"]

s.add_dependency('exifr')
s.add_dependency('rmagick')

s.homepage =
'http://github.com/ishwinder/enbake_attach'
s.license = 'MIT'
end
4 changes: 0 additions & 4 deletions init.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
# Due to the sequence of dependency processing and plugin initialization, these statements cannot be used to auto-install
# missing gems -they are here solely for documentation.
config.gem 'exifr', :version => '>=1.0.3'
config.gem 'rmagick', :version => '>=2.7.2', :lib => 'RMagick'
config.gem 'aws-s3', :version => '>=0.6.2', :lib => 'aws/s3'

require 'geometry'
require 'hapgood/attach'

Expand Down
2 changes: 2 additions & 0 deletions lib/enbake_attach.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require 'geometry'
require 'hapgood/attach'
22 changes: 20 additions & 2 deletions lib/hapgood/attach.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'hapgood/attach/sources'
require 'base64'

module Hapgood # :nodoc:
module Attach # :nodoc:
Expand Down Expand Up @@ -35,7 +36,7 @@ def has_attachment(options = {})
options[:store] ||= Proc.new {|i, e| "file://localhost#{::File.join(RAILS_ROOT, 'public', 'attachments', [i,e].compact.join('.'))}"}

# doing these shenanigans so that #attachment_options is available to processors and backends
class_inheritable_accessor :attachment_options
class_attribute :attachment_options
self.attachment_options = options

# only need to define these once on a class
Expand Down Expand Up @@ -113,7 +114,7 @@ def url
# Setter for virtual url attribute used to reference external data sources.
def url=(u)
@url = u
return unless u
return unless u && !u.blank?
destroy_source # Discard any existing source
begin
self.source = Sources::Base.load(::URI.parse(u))
Expand All @@ -122,6 +123,16 @@ def url=(u)
end
end

def blob=(bl)
return unless bl
destroy_source # Discard any existing source
begin
self.source = Sources::Base.load(Base64.decode64(bl[:data]), blob_metadata(bl))
rescue => e # Can't do much here -we have to wait until the validation phase to resurrect/reconstitute errors
logger.error("Attach: *********ERROR: can't load blob data (#{e})")
end
end

# Get the source. Rescue exceptions and make them errors on the source virtual attribute.
def source
@source ||= uri && Sources::Base.reload(uri, stored_metadata)
Expand Down Expand Up @@ -232,6 +243,13 @@ def cgi_metadata(data)
end
end

def blob_metadata(b)
Hash.new.tap do |md|
md[:filename] = b[:filename]
md[:mime_type] = ::Mime::Type.lookup(b[:content_type])
end
end

# Extract stored metadata from attributes to enrichen a purely binary source to the same level as a CGI-supplied source.
def stored_metadata
%w(filename mime_type).inject(Hash.new) {|hash, key| hash[key.to_sym] = self.send(key.to_sym);hash}
Expand Down
15 changes: 13 additions & 2 deletions lib/hapgood/attach/sources/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ module Sources
# data : A blob (string) of the attachment's data
# tempfile : A tempfile of the attachment
class Base
class_inheritable_accessor :tempfile_path, :instance_writer => false
write_inheritable_attribute(:tempfile_path, File.join(RAILS_ROOT, 'tmp', 'attach'))
class_attribute :tempfile_path
self.tempfile_path = File.join(RAILS_ROOT, 'tmp', 'attach')

attr_reader :error, :data

Expand Down Expand Up @@ -104,6 +104,17 @@ def change_image(&block)
is.change_image(&block)
end

def change_frame(i, &block)
is = self.is_a?(Sources::Rmagick) ? self : Sources::Rmagick.new(self)
is.change_frame(i, &block)
end

def frame_count
raise "Unable to process source" unless processable?
is = self.is_a?(Sources::Rmagick) ? self : Sources::Rmagick.new(self)
is.frame_count
end

def valid?
error.nil?
end
Expand Down
4 changes: 4 additions & 0 deletions lib/hapgood/attach/sources/blob.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ module Attach # :nodoc:
module Sources
# Methods for blob sources
class Blob < Hapgood::Attach::Sources::Base
def self.load(d, m={})
new(d, m)
end

# Does this source persist at the URI independent of this application?
def persistent?
false
Expand Down
26 changes: 26 additions & 0 deletions lib/hapgood/attach/sources/rmagick.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,32 @@ def change_image(&block)
self
end

# Method to get a particular frame.
def frame_image(fi)
@image ||= begin
format = self.class.format_for_mime_type(@source.mime_type)
read_spec = "#{@source.tempfile.path}[#{fi}]"
read_spec = "#{format}:" + read_spec if format
::Magick::Image.read(read_spec).first
end
end

# Method to yield a particular frame.
# TODO: These methods should typically merge away with change_image methods above.
def change_frame(fi, &block)
yield frame_image(fi)
# TODO: Typical attach module dependencies. Always take care of these globals.
@tempfile = nil
@uri = nil # Once transformed, all external sources are invalid.
@blob = nil # Once transformed, we need to reset the data. Now the getter can lazily load the blob.
@persistent = false
self
end

def frame_count
::Magick::Image.read(@source.tempfile.path).length
end

private
# Extract useful information from (ExiF | IPTC) header, if possible.
def exif_data
Expand Down