项目作者: maxim

项目描述 :
Better ImageMagick for Ruby
高级语言: Ruby
项目地址: git://github.com/maxim/skeptick.git
创建时间: 2012-12-14T00:15:57Z
项目社区:https://github.com/maxim/skeptick

开源协议:MIT License

下载


Skeptick: Better ImageMagick for Ruby

Build Status
Code Climate
Dependency Status

Skeptick is an all-purpose DSL for building and running ImageMagick commands.
It helps you build any transformations, from trivial resizes to complex mask
algorithms and free drawing. In a nutshell, Skeptick is nothing more than a
string manipulator and a process spawner. That’s all it’s meant to be. However,
with Skeptick you get quite a few advantages over using plain shell-out or other
libraries.

What you get

  • Clean Ruby syntax to build ImageMagick commands
  • Composable Image objects
  • ImageMagick’s STDERR output revealed in a Ruby exception
  • Ability to save intermediate images for debugging
  • Minimal memory consumption on shell-outs thanks to
    posix-spawn
  • Emphasis on performing the whole transformation in a single command

Installation

Add this line to your application’s Gemfile:

  1. gem 'skeptick'

And then execute:

  1. $ bundle

Or install it yourself as:

  1. $ gem install skeptick

Usage

To use Skeptick, you simply require it and include the module into your class.

  1. require 'skeptick'
  2. class MyClass
  3. include Skeptick
  4. def convert_some_image
  5. cmd = convert(to: 'result.png') do
  6. # ...
  7. end
  8. cmd.run
  9. end
  10. end

The cmd object seen in above example can be inspected to see the exact command
that Skeptick will run. Simply use cmd.inspect or cmd.to_s. Skeptick never
runs anything until you call run (except for one very special case), so you
can inspect commands all you want before executing them.

If you don’t want to require all of Skeptick, you can just require the core, and
and select any specific sugar you want.

  1. require 'skeptick/core'
  2. require 'skeptick/sugar/resized_image'
  3. require 'skeptick/sugar/compose'

See the lib/skeptick/sugar dir for all the goodies.

In Rails Skeptick will automatically use Rails.logger and Rails.root as
cd_path. You can also configure your own.

  1. Skeptick.logger = MyLogger.new
  2. Skeptick.cd_path = '/some/dir'

You can enable debug_mode to display every executed command in the log.

  1. Skeptick.debug_mode = true

Security Note

Never insert any user input into any of Skeptick’s commands. This should be
obvious. Skeptick executes strings in your shell.

DSL

Skeptick Logo

Take a look at logo.rb to see thow this logo was generated.

A lot is going on in the above script, no worries, it’s just a showcase. I bet
the first thing you noticed is a shitstorm of little method names like canvas,
font, write, draw, etc. Well, they are all sugar. We will cover sugar
below.

There are actually only 2 useful methods in all of Skeptick: convert and
set.

Convert

convert can be used both standalone and inside another convert. You could
say this.

  1. command = convert('image1.png', to: 'image2.png') do
  2. set :resize, '200x200'
  3. end
  4. # OUTPUT:
  5. # convert image1.png -resize 200x200 image2.png

Or you could put it inside, and it will become a parenthesized subcommand.

  1. command = convert('image1.png', to: 'image2.png') do
  2. convert do
  3. set '+clone' # pull in image1 into parentheses
  4. set :resize, '100x100' # resize image1's clone in memory
  5. end
  6. set '-compose', 'over'
  7. set '-composite'
  8. end
  9. # OUTPUT:
  10. # convert image1.png ( +clone -resize 100x100 )
  11. # -compose over -composite image2.png

If you love parentheses a lot, you could nest convert infinitely. However,
ImageMagick’s clone, delete, and swap are your friends, learn them to
cure parenthethitis.

Oh, speaking of nesting — we can reuse that whole command inside another command
by passing it to convert in place of an image filepath.

  1. new_command = convert(command, to: 'whatever.png') do
  2. set '-resize', '300x300'
  3. end
  4. # OUTPUT:
  5. # convert
  6. # ( image1.png ( +clone -resize 100x100 ) -compose over -composite )
  7. # -resize 300x300 whatever.png

See what I did there? The command from previous snippet is passed into
convert. If you have a convert object in a variable, you can use it inside
another convert object down the line. Nesting possibilities are endless.

The same snippet could also be written like this.

  1. new_command = convert(to: 'whatever.png') do
  2. image command
  3. set :resize, '300x300'
  4. end

2 differences: 1 - instead of passing in command as argument we declare it
inside the block. 2 - resize is a symbol. Any symbol passed into set
automatically becomes a string with dash in front of it. Speaking of set.

Set

set adds stuff to your command. You can give it any various arguments, it
doesn’t care.

  1. # Works the same way:
  2. set '-resize', '100x100'
  3. set :resize, '100x100'
  4. # bad, won't work
  5. set '-resize 100x100'

Watch out for the fact that it shell-escapes every argument, so if you write set '-resize foo', you will get an error, since the space will be escaped, and shell would treat that whole string as single word.`

In addition to set there are also prepend and append to put stuff at the
beginning or end of a command, but they are rarely useful, and mostly for
implementing your own sugar.

Sugar

Skeptick comes with a bunch of sugar. When you require Skeptick, you can simply
require everything. This includes all the sugar functionality.

  1. require 'skeptick'

However, you can require just the core stuff described above, and select any
sugar you want.

  1. require 'skeptick/core'
  2. require 'skeptick/sugar/compose'

Compose Sugar

Compose is sugar that adds compose shortcut to Skeptick’s DSL.

  1. command = compose(:multiply, 'a.png', 'b.png', to: 'out.png') do
  2. set :resize, '200x200'
  3. end
  4. # OUTPUT:
  5. # convert a.png b.png -compose multiply -resize 200x200 -composite out.png

It takes the blending type as the first argument, and injects some extra stuff
into the resulting command.

As with convert, you don’t have to list your images as method arguments.
Instead you could declare them inside the block using the image method. The
following command does the same thing.

  1. command = compose(:multiply, to: 'out.png') do
  2. image 'a.png'
  3. convert 'b.png'
  4. set :resize, '200x200'
  5. end

Note: image is alias of convert.

Since most of Skeptick’s power comes from the ability to infinitely nest things,
here’s an example involving a nested compose.

  1. command = convert('image1.png', to: 'result.png') do
  2. compose(:multiply) do
  3. image 'image2.png[200x200]'
  4. convert 'image3.png' do
  5. set :unsharp, '0x5'
  6. end
  7. end
  8. end
  9. # OUTPUT:
  10. # convert
  11. # image1.png image2.png[200x200] ( image3.png -unsharp 0x5 ) -compose
  12. # multiply -composite result.png"

Notice how we nest compose inside of convert, and then convert inside of
compose.

Compose Operators

This is more of a gimmick than a real feature, but you can use math operators
like +, -, *, /, &, | to compose images. These are all based on
compose method. Here’s a multiply example.

  1. image1 = image('foo.png')
  2. image2 = image('bar.png')
  3. result = convert(image1 * image2, to: 'baz.png')
  4. # OUTPUT:
  5. # convert foo.png bar.png -compose multiply -composite baz.png

As you can see, this is equivalent of simply using compose.

  1. # Same thing
  2. result = compose(:multiply, 'foo.png', 'bar.png', to: 'baz.png')

Check out lib/skeptick/sugar/compose.rb for
what these operators do.

clone, delete, swap

Skeptick provides methods clone, delete, and swap to
manipulate declared images in a sequence, just like in ImageMagick CLI.

  1. command = compose(:over, 'image1.png', to: 'result.png') do
  2. # You could think of image sequence as a ruby array. Here's what it would
  3. # look like right now.
  4. # [ 'image1.png' ]
  5. compose(:multiply) do
  6. image 'mask.png' # loading another image for this operation
  7. clone(0) # cloning image1.png from outside "into parentheses"
  8. end
  9. # Sequence at this point:
  10. # [ 'image1.png', 'result of compose(:multiply)' ]
  11. delete(0) # deleting image1.png from the sequence and from memory
  12. # Sequence at this point:
  13. # [ 'result of compose(:multiply)' ]
  14. # At this point the only image loaded in memory is the one produced by the
  15. # compose(:multiply) command above. Let's load another one.
  16. image 'image2.png'
  17. # Sequence at this point:
  18. # [ 'result of compose(:multiply)', 'image2.png' ]
  19. # Now we have two images in the sequence. We can swap them in case we need
  20. # to change their order.
  21. swap
  22. # Sequence at this point:
  23. # [ 'image2.png', 'result of compose(:multiply)' ]
  24. # Now image2.png is first in the sequence, and the output of
  25. # compose(:multiply) is second. Since our outermost command is compose(:over),
  26. # at this point these 2 images will be composed over each other, and the
  27. # result written to result.png.
  28. end
  29. # OUTPUT
  30. # convert
  31. # image1.png ( mask.png -clone 0 -compose multiply -composite )
  32. # -delete 0 image2.png +swap -compose over -composite result.png

You can use clone and delete to refer to multiple images at once by passing
mutliple indexes as arguments, like clone(0,1,2) or delete(0,1). Ranges are
also accepted. Without any arguments clone and delete are translated to
ImageMagick’s +clone and +delete. They then refer to the last image in the
sequence. Same with swap - you can provide two indexes in arguments like
swap(1,3) to swap any 2 images in the sequence, or without arguments it’ll
act as +swap - which swaps last two images.

Write

Sometimes you might want to take a look at an intermediate image that’s being
generated inside parentheses, nested somewhere in your command. You can do so
with the help of write '/path/to/img.png', which is defined in
skeptick/sugar/write.rb.

  1. command = convert(to: 'result.png') do
  2. compose(:multiply, 'a.png', 'b.png') do
  3. write '~/Desktop/debug.png'
  4. end
  5. set :resize, '200x200'
  6. end

In this case the result of inner compose command will be saved to desktop
without affecting anything else. This is a feature that already exists in
ImageMagick, as you can see for yourself from generated command:

  1. convert
  2. ( a.png b.png -compose multiply -composite -write ~/Desktop/debug.png )
  3. -resize 200x200 result.png

Documentation is to be continued…

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request