Module: AttachmentSaver::Processors::Image
- Included in:
- GdkPixbuf, ImageScience, ImageSize, MiniMagick, RMagick
- Defined in:
- lib/processors/image.rb
Overview
shared code for all image processors
Defined Under Namespace
Modules: Operations
Constant Summary collapse
- DEFAULT_VALID_IMAGE_TYPES =
%w(image/jpeg image/png image/gif).freeze
Class Method Summary collapse
-
.from_geometry_string(geom) ⇒ Object
unpacks a resize geometry string into an array contining the corresponding image operation method name (see Operations below, plus any from your chosen image processor) followed by the arguments to that method.
Instance Method Summary collapse
- #before_validate_attachment ⇒ Object
-
#build_derived(attributes) ⇒ Object
builds a new derived image model instance, but doesn’t save it.
-
#derived_image? ⇒ Boolean
determines if this is a derived image.
- #image? ⇒ Boolean
- #process_attachment(filename) ⇒ Object
- #process_attachment? ⇒ Boolean
-
#update_derived(derived, attributes) ⇒ Object
updates an existing derived image model instance, and queues it for save when this model is saved.
- #valid_image_type ⇒ Object
-
#want_format?(derived_name, derived_width, derived_height) ⇒ Boolean
determines if a particular configured derived image should be created.
Class Method Details
.from_geometry_string(geom) ⇒ Object
unpacks a resize geometry string into an array contining the corresponding image operation method name (see Operations below, plus any from your chosen image processor) followed by the arguments to that method.
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/processors/image.rb', line 116 def self.from_geometry_string(geom) match, w, cross, h, flag = geom.match(/^(\d+\.?\d*)?(?:([xX])(\d+\.?\d*)?)?([!%<>#*])?$/).to_a raise "couldn't parse geometry string '#{geom}'" if match.nil? || (w.nil? && h.nil?) h = w unless cross # there's <w>x<h>, there's <w>x, there's x<h>, and then there's just plain <n>, which means <w>=<h>=<n> return [:scale_by, (w || h).to_f/100, (h || w).to_f/100] if flag == '%' operation = case flag when nil then :scale_to_fit when '!' then w && h ? :squish : :scale_to_fit when '>' then :shrink_to_fit when '<' then :expand_to_fit when '*' then :scale_to_cover when '#' then :cover_and_crop end [operation, w ? w.to_i : nil, h ? h.to_i : nil] end |
Instance Method Details
#before_validate_attachment ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/processors/image.rb', line 39 def unless uploaded_file.nil? || derived_image? return false unless valid_image_type examine_image end rescue ImageProcessorError # we examine all files, regardless of whether the client browser labelled them an # image, because they may be an image with the wrong extension or content type. # but this will raise for non-image files, so ignore such errors but make sure # image? will return false, if it doesn't already. self.content_type = "application/octet-stream" if image? end |
#build_derived(attributes) ⇒ Object
builds a new derived image model instance, but doesn’t save it. provided so apps can easily override this step.
100 101 102 |
# File 'lib/processors/image.rb', line 100 def build_derived(attributes) formats.build(attributes) end |
#derived_image? ⇒ Boolean
determines if this is a derived image. used to prevent infinite recursion when storing the derived images in the same model as the originals (and as a secondary benefit avoid unnecessary work examining images for derived images, for which the full metadata is already filled in by the resizing code).
60 61 62 |
# File 'lib/processors/image.rb', line 60 def derived_image? respond_to?(:format_name) && !format_name.blank? end |
#image? ⇒ Boolean
12 13 14 15 16 |
# File 'lib/processors/image.rb', line 12 def image? return false if content_type.blank? parts = content_type.split(/\//) parts.size == 2 && parts.first.strip == 'image' end |
#process_attachment(filename) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/processors/image.rb', line 72 def (filename) with_image(filename) do |original_image| unless self.class.[:formats].blank? old_children = new_record? ? {} : formats.group_by(&:format_name) self.class.[:formats].each do |derived_name, resize_format| derived_attributes = process_image(original_image, derived_name, resize_format) if derived_attributes if old_children[derived_name.to_s] update_derived(old_children[derived_name.to_s].pop, derived_attributes) else build_derived(derived_attributes) end end end old_children = old_children.values.flatten formats.destroy(old_children) unless old_children.blank? # remove any old derived images for formats for which want_format? now returned false end end rescue AttachmentSaverError raise rescue NotImplementedError raise rescue Exception => ex raise ImageProcessorError, "#{ex.class}: #{ex.message}", ex.backtrace end |
#process_attachment? ⇒ Boolean
52 53 54 |
# File 'lib/processors/image.rb', line 52 def image? && !self.class.[:formats].blank? && !derived_image? end |
#update_derived(derived, attributes) ⇒ Object
updates an existing derived image model instance, and queues it for save when this model is saved. provided so apps can easily override this step.
106 107 108 109 110 111 |
# File 'lib/processors/image.rb', line 106 def update_derived(derived, attributes) derived.attributes = attributes @updated_derived_children ||= [] @updated_derived_children << derived # we don't want to save it just yet in case processing subsequent images fail; rails will automatically save it if we're a new record, but we have to do it ourselves in an after_save if not derived end |
#valid_image_type ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/processors/image.rb', line 18 def valid_image_type valid_image_types = self.class.[:valid_image_types] || DEFAULT_VALID_IMAGE_TYPES uploaded_file.rewind magic = MimeMagic.by_magic(uploaded_file) if magic.nil? # if it doesn't look like an image, make sure it's not labelled as an image self.content_type = 'application/octet-stream' if image? || content_type.nil? elsif !valid_image_types.include?(magic.type) # overwrite the content type given by the untrusted client with the real content type; it may get refined later by the image processor self.content_type = magic.type else # seems legit return true end errors.add(:content_type, "is invalid") if respond_to?(:errors) false end |
#want_format?(derived_name, derived_width, derived_height) ⇒ Boolean
determines if a particular configured derived image should be created. this implementation, which always returns true, may be overridden by applications to make certain formats conditional (for example, only creating certain larger sizes if the original image was at least that large).
68 69 70 |
# File 'lib/processors/image.rb', line 68 def want_format?(derived_name, derived_width, derived_height) true end |