diff --git a/enbake_attach.gemspec b/enbake_attach.gemspec new file mode 100644 index 0000000..c6e31d3 --- /dev/null +++ b/enbake_attach.gemspec @@ -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 \ No newline at end of file diff --git a/init.rb b/init.rb index a6182a5..f59e031 100644 --- a/init.rb +++ b/init.rb @@ -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' diff --git a/lib/enbake_attach.rb b/lib/enbake_attach.rb new file mode 100644 index 0000000..14f05c5 --- /dev/null +++ b/lib/enbake_attach.rb @@ -0,0 +1,2 @@ +require 'geometry' +require 'hapgood/attach' \ No newline at end of file diff --git a/lib/hapgood/attach.rb b/lib/hapgood/attach.rb index a0fc222..01cedf2 100644 --- a/lib/hapgood/attach.rb +++ b/lib/hapgood/attach.rb @@ -1,4 +1,5 @@ require 'hapgood/attach/sources' +require 'base64' module Hapgood # :nodoc: module Attach # :nodoc: @@ -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 @@ -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)) @@ -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) @@ -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} diff --git a/lib/hapgood/attach/sources/base.rb b/lib/hapgood/attach/sources/base.rb index 46632f3..8e50343 100644 --- a/lib/hapgood/attach/sources/base.rb +++ b/lib/hapgood/attach/sources/base.rb @@ -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 @@ -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 diff --git a/lib/hapgood/attach/sources/blob.rb b/lib/hapgood/attach/sources/blob.rb index 52a1554..cb1bf3a 100644 --- a/lib/hapgood/attach/sources/blob.rb +++ b/lib/hapgood/attach/sources/blob.rb @@ -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 diff --git a/lib/hapgood/attach/sources/rmagick.rb b/lib/hapgood/attach/sources/rmagick.rb index 7113166..e929af0 100644 --- a/lib/hapgood/attach/sources/rmagick.rb +++ b/lib/hapgood/attach/sources/rmagick.rb @@ -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