class Thingfish::Processor::Image
Constants
- IGNORED_MIMETYPES
An array of mediatypes to ignore, even though ImageMagick claims it groks them
- REVISION
Version control revision
- VERSION
Package version
Attributes
The mediatypes the plugin can generated in a response, as ThingFish::AcceptParam objects
The mediatypes the plugin accepts in a request, as ThingFish::AcceptParam objects
The Hash of formats and the operations they support.
Public Instance Methods
Returns true
if the given media type
is one the processor handles. Overridden so the types can be used by the instance.
# File lib/thingfish/processor/image.rb, line 80 def handled_type?( type ) self.log.debug "Looking for handled type for: %p" % [ type ] result = self.handled_types.find {|handled_type| type =~ handled_type } self.log.debug " found: %p" % [ result ] return result end
Return a human-readable representation of the receiving object suitable for debugging.
# File lib/thingfish/processor/image.rb, line 129 def inspect return "#<%p:%#x %d supported image formats, %d readable, %d writable>" % [ self.class, self.object_id * 2, self.supported_formats.size, self.handled_types.size, self.generated_types.size, ] end
Synchronous processor API – extract metadata from uploaded images.
# File lib/thingfish/processor/image.rb, line 90 def on_request( request ) self.log.debug "Image-processing %p" % [ request ] image = case request.body when StringIO self.log.debug " making a single image from a StringIO" Magick::Image.from_blob( request.body.read ) else path = request.body.path self.log.debug " making a flattened image out of %p" % [ path ] path = path.to_s + '[0]' # ImageMagick, read a single frame list = Magick::ImageList.new( path ) list.flatten_images end image = image.first if image.respond_to?( :first ) self.log.debug " image is: %p" % [ image ] metadata = self.extract_image_metadata( image ) self.log.debug " extracted image metadata: %p" % [ metadata ] request.add_metadata( metadata ) self.log.debug " going to generate a thumbnail..." self.generate_thumbnail( image, metadata['title'] ) do |thumbio, thumb_metadata| self.log.debug " generated: %p (%p)" % [ thumbio, thumb_metadata ] request.add_related_resource( thumbio, thumb_metadata ) end self.log.debug " destroying the image to free up memory" rescue Magick::ImageMagickError => err self.log.error "Problem while processing file %p: %s" % [ err.class, err.message ] self.log.debug { err.backtrace.join( "\n " ) } ensure image.destroy! if image end
Protected Instance Methods
Extract metadata from the given image
(a Magick::Image object) and return it in a Hash.
# File lib/thingfish/processor/image.rb, line 146 def extract_image_metadata( image ) metadata = {} metadata.merge!( self.get_regular_metadata(image) ) metadata.merge!( self.get_exif_metadata(image) ) return metadata end
Return an Array of Strelka::HTTPRequest::MediaType objects for the formats that the processor is capable of writing.
# File lib/thingfish/processor/image.rb, line 307 def find_generated_types( supported_formats ) return supported_formats. select {|type, op| op.can_write? }. collect {|type, op| Strelka::HTTPRequest::MediaType.parse(type) } end
Return Strelka::HTTPRequest::MediaType objects for the formats that the processor is capable of reading.
# File lib/thingfish/processor/image.rb, line 298 def find_handled_types( supported_formats ) return supported_formats. select {|type, op| op.can_read? }. collect {|type, op| Strelka::HTTPRequest::MediaType.parse(type) } end
Transform the installed ImageMagick's list of formats into AcceptParams for easy comparison later.
# File lib/thingfish/processor/image.rb, line 265 def find_supported_formats formats = {} raise "Config database doesn't have any mimetypes" if Mongrel2::Config.mimetypes.empty? # A hash of image formats and their properties. Each key in the returned # hash is the name of a supported image format. Each value is a string in # the form "BRWA". The details are in this table: # B is "*" if the format has native blob support, and "-" otherwise. # R is "r" if ×Magick can read the format, and "-" otherwise. # W is "w" if ×Magick can write the format, and "-" otherwise. # A is "+" if the format supports multi-image files, and "-" otherwise. Magick.formats.each do |ext,support| ext = ".#{ext.downcase}" self.log.debug "Looking for mediatype for ext: %s (%p)" % [ ext, support ] mimetype = Mongrel2::Config.mimetypes[ ext ] or next self.log.debug " mimetype is: %p" % [ mimetype ] next if IGNORED_MIMETYPES.include?( mimetype ) operations = MagickOperations.new( ext, support ) self.log.debug " registering image format %s (%s)" % [ mimetype, operations ] formats[ mimetype ] = operations end self.log.debug "Registered mimetype mapping for %d of %d supported image types" % [ formats.keys.length, Magick.formats.length ] return formats end
Create a thumbnail from the given image
and return it in a string along with any associated metadata.
# File lib/thingfish/processor/image.rb, line 183 def generate_thumbnail( image, title ) dimensions = self.class.thumbnail_dimensions self.log.debug "Making thumbnail of max dimensions: [%d X %d]" % dimensions thumb = image.resize_to_fit( *dimensions ) imgdata = StringIO.new imgdata << thumb.to_blob {|img| img.format = 'JPG' } imgdata.rewind metadata = self.extract_image_metadata( thumb ) metadata.merge!({ format: thumb.mime_type, relationship: 'thumbnail', title: "Thumbnail of %s" % [ title || image.inspect ], extent: imgdata.size, }) self.log.debug " made thumbnail for %p" % [ image ] yield( imgdata, metadata ) thumb.destroy! end
Fetch exif metadata and return it as a Hash.
# File lib/thingfish/processor/image.rb, line 170 def get_exif_metadata( image ) exif_pairs = image.get_exif_by_entry exif_pairs.reject! {|name, val| name == 'unknown' || val.nil? } exif_pairs.collect! do |name, val| newname = name.gsub(/\B([A-Z])(?=[a-z])/) { '_' + $1 }.downcase [ "exif:#{newname}", val ] end return Hash[ exif_pairs ] end
Fetch regular image metadata as a Hash.
# File lib/thingfish/processor/image.rb, line 157 def get_regular_metadata( image ) return { 'image:height' => image.rows, 'image:width' => image.columns, 'image:depth' => image.depth, 'image:density' => image.density, 'image:gamma' => image.gamma, 'image:bounding_box' => image.bounding_box.to_s, } end
Set up a new Filter object
# File lib/thingfish/processor/image.rb, line 53 def initialize( * ) # :notnew: super @supported_formats = find_supported_formats() @handled_types = find_handled_types( @supported_formats ) @generated_types = find_generated_types( @supported_formats ) end