Dragonfly

Image/asset management for winners

GitHub Repository

Processors

A Processor modifies content, e.g. resizing an image, converting audio to mp3 format, etc.

They can be added using a block

Dragonfly.app.configure do
  processor :shrink do |content, *args|
    # ...
  end
  # ...
end

or providing an object that responds to call (MyProcessor in this case)

Dragonfly.app.configure do
  processor :shrink, MyProcessor
  # ...
end

Using the processor

The processor is available as a method to Job objects

image = Dragonfly.app.fetch('some/uid')
smaller_image = image.shrink

and Attachment objects

image = my_model.photo
smaller_image = image.shrink

Furthermore, a bang! method is provided, which operates on self

image.shrink!

You can pass arguments, which will be passed on to the processor block

processor :shrink do |content, amount, quality|
  # ...
end
image.shrink(4, 30)

Implementing the processor

The content object yielded to the block/call method is a Dragonfly::Content - see the doc for methods it provides.

The processor’s job is to use methods on content to modify it - the return value of the processor block is not important.

Updating content and metadata

The primary method to use to update content is Content#update. It can take a String, Pathname, File or Tempfile, and optionally metadata to add.

processor :shrink do |content|
  # ...
  content.update(some_file, 'some' => 'meta')
end

Another way of updating metadata is with add_meta

content.add_meta('some' => 'meta')

NOTE meta data should be serializable to and from JSON.

Using shell commands

To update using the shell, you can use Content#shell_update

processor :shrink do |content|
  content.shell_update do |old_path, new_path|
    "/usr/bin/shrink #{old_path} -o #{new_path}"  # The command sent to the command line
  end
end

The yielded old_path and new_path above will always exist.

By default every argument is shell-escaped so pipes, etc. won’t work. You can avoid this with escape: false.

Change the output extension with the :ext option.

processor :shrink do |content|
  content.shell_update ext: 'jpg', escape: false do |old_path, new_path|
    "/usr/bin/shrink #{old_path} > #{new_path}"  # The command sent to the command line
  end
end

Using pre-registered processors

To update using a pre-registered processor, use Content#process!

processor :greyscale do |content|
  content.process! :convert, "-type Grayscale"
end

Updating the url

It is also possible for a processor to (optionally) update the url for a given job. For example, suppose we have a configured url format

url_format '/:basename-:style.:ext'

A job

job = Dragonfly.app.fetch('some_uid')

will have a url

job.url # ===> "?job=W1siZiIsInNvbWVfdWlkIl1d"

Here, basename, style and ext have not been set on the job’s url_attributes, so they don’t appear in the url.

Setting the name will set basename and ext.

job.url  # ===> "?job=W1siZiIsInNvbWVfdWlkIl1d"
job.url_attributes.name = 'hello.txt'
job.url  # ===> "/hello.txt?job=W1siZiIsInNvbWVfdWlkIl1d"

Note that this happens automatically for models when a xxx_name accessor is provided.

We can tell our processor to add the style part of the url by implementing the method update_url (note that we cannot register the processor as a block in this case)

class ShrinkProcessor
  def call(content, *args)
    # ...
  end

  def update_url(attrs, *args) # attrs is Job#url_attributes, which is an OpenStruct-like object
    attrs.style = 'shrunk'
  end
end

Dragonfly.app.configure do
  processor :shrink, ShrinkProcessor.new
  # ...
end

Now the processor adds the ‘style’ part to the url

job.url        # ===> "/hello.txt?job=W1siZiIsInNvbWVfdWlkIl1d"
job.shrink.url # ===> "/hello-shrunk.txt?job=W1siZiIsInNvbWVfdWlkIl1d"

If the processor accepts extra arguments then these are also passed to update_url.

ImageMagick

The ImageMagick plugin adds a few processors - see the doc for more details.

If you’re defining a new processor you can make use of the convert command in Dragonfly::ImageMagick::Commands, e.g.

include Dragonfly::ImageMagick::Commands

processor :fancy do |content|
  convert(content, '-sigmoidal-contrast 4,0%')
end

which corresponds to the command-line

convert <original_path> -sigmoidal-contrast 4,0% <new_path>

As with thumb, you can specify a few more options

convert(
  content,
  '-sigmoidal-contrast 4,0%',
  'format' => 'jpg',
  'frame' => 12,
  'delegate' => 'mpeg',
  'input_args' => 'I go before the <original_path> arg'
)