Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/afeld/magickly
image manipulation as a (plugin-able) service
https://github.com/afeld/magickly
Last synced: 3 months ago
JSON representation
image manipulation as a (plugin-able) service
- Host: GitHub
- URL: https://github.com/afeld/magickly
- Owner: afeld
- License: mit
- Created: 2011-03-23T23:34:06.000Z (over 13 years ago)
- Default Branch: master
- Last Pushed: 2016-02-01T07:24:25.000Z (over 8 years ago)
- Last Synced: 2024-01-17T13:54:36.706Z (5 months ago)
- Language: Ruby
- Homepage: http://magickly.afeld.me
- Size: 570 KB
- Stars: 180
- Watchers: 6
- Forks: 35
- Open Issues: 14
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE.txt
Lists
- awesome-ruby - magickly - able) service (Imagery)
README
# ![Magickly - image manipulation as a (plugin-able) service](http://magickly.afeld.me/images/logo.jpg)
Built as a practical wrapper of Imagemagick which handles caching, c/o the [Dragonfly](http://markevans.github.com/dragonfly/) gem.
Say the base URL is the hosted version of this app, [magickly.afeld.me](http://magickly.afeld.me). The image URL is appended to the query string as a `src=`, followed by any of the supported operations below. Multiple operations can be combined, and will be applied in order.
If no query params are provided, a simple sandbox page is displayed. Try it here:
[magickly.afeld.me](http://magickly.afeld.me)
More insights:
* [Blog post](https://aidan.jux.com/nerdery/310516) about how it's used at Jux
* Talk: *Magickly, Mustachio, & Stateless APIs* ([slides](https://docs.google.com/presentation/d/1vuXqmMOssslx3nRxqWh1e3SgGN7_euYdVMIWm94DDPA/edit?usp=sharing))
* [12-minute overview version](https://www.youtube.com/watch?v=X3VdlBDCJSA) at [Code Genius](http://code.genius.com/)
* [49-minute in-depth version](http://www.hakkalabs.co/articles/anatomy-ruby-gem-magickly) at [Anatomy of a Ruby Gem](http://www.meetup.com/Anatomy-of-a-Ruby-Gem/events/163904202/)## Installation
[Compatible](http://travis-ci.org/#!/afeld/magickly) with Ruby 1.9.3, 2.0 and 2.1, and jRuby (in 1.9 mode). Requires Imagemagick >= v6.2.4.
$ gem install magickly
## Running the App
A few options:
### A. Run the app directly
# in the app directory:
$ gem install thin
$ thin startThe app can be accessed at [http://localhost:3000](http://localhost:3000).
When running as an app, Rack::Cache is used to cache generated versions of images. These cached files and metadata are stored in the tmp/ directory and will get regenerated as necessary.
### B. Use as an endpoint in another Rack app
As an example, to have magickly accessible at `/magickly` in a Rails app:
# Gemfile
gem 'magickly', '~> 1.1'
# config/routes.rb
match '/magickly', :to => Magickly::App, :anchor => falseFor more info, see [Rails Routing from the Outside In](http://guides.rubyonrails.org/routing.html#routing-to-rack-applications) or Michael Raidel's [Mount Rails apps in Rails 3](http://inductor.induktiv.at/blog/2010/05/23/mount-rack-apps-in-rails-3/).
## Processing Parameters
*See the [Dragonfly documentation](http://markevans.github.com/dragonfly/file.ImageMagick.html) for more details about the permitted* `geometry` *values.*
### src=*url* (required)
The URL of the original image.
### brightness_contrast=*br.* x *con.*
*brightness* and *contrast* are percentage change, between -100 and 100. For example, to increase contrast by 20% but leave brightness unchanged, use `brightness_contrast=0x20`.
![tanned imagemagick logo](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&brightness_contrast=-10x50)
[http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&brightness_contrast=-10x50](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&brightness_contrast=-10x50)
### flip=true
![flipped imagemagick logo](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&flip=true)
[http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&flip=true](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&flip=true)
### flop=true
![flopped imagemagick logo](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&flop=true)
[http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&flop=true](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&flop=true)
### glow=*amount*,*softness*
where `amount` is a float >= 1.0, and `softness` is an int >= 0.
![glowing imagemagick logo](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&glow=1.2,20)
[http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&glow=1.2,20](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&glow=1.2,20)
### greyscale=true
![flopped imagemagick logo](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&greyscale=true)
[http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&greyscale=true](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&greyscale=true)
### halftone=*threshold*
where *threshold* is a value between 0 and 100.
![halftone imagemagick logo](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&halftone=60)
[http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&halftone=60](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&halftone=60)
### jcn=true
![JCN imagemagick logo](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&jcn=true)
[http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&jcn=true](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&jcn=true)
### resize=*geometry*
![resized imagemagick logo](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&resize=100x100)
[http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&resize=100x100](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&resize=100x100)
### rotate=*degrees*
![rotated imagemagick logo](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&rotate=45)
[http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&rotate=45](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&rotate=45)
### saturation=*percentage*
*percentage* is the percentage of variation: a positive integer. 100 means no change. For example, to increase saturation by 50%, use `saturation=150`.
![saturated imagemagick logo](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&saturation=150)
[http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&saturation=150](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&saturation=150)
### tilt_shift=true
![tilt-shifted imagemagick logo](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&tilt_shift=true)
[http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&tilt_shift=true](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&tilt_shift=true)
### thumb=*geometry*
![thumbnail of imagemagick logo](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&thumb=200x100%23)
[http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&thumb=200x100%23](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&thumb=200x100%23)
(note: the `%23` in the geometry string above is an encoded '`#`', which tells Dragonfly to fill the dimensions and crop)
### two_color=true
![two color imagemagick logo](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&two_color=true)
[http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&two_color=true](http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&two_color=true)
## Alternate Syntax
Some CDNs are jerks and don't respect query params on resources (_ahem_ CLOUDFRONT _ahem_) when caching. To use this syntax:
* replace the question mark that starts the query string (`?`) with `q/`
* replace the ampersands (`&`) and equals signs (`=`) with forward slashes (`/`)
* make sure the `src` is encoded - this can be done in Javascript with `encodeURIComponent()`Therefore, instead of
http://magickly.afeld.me/?src=http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Imagemagick-logo.png/200px-Imagemagick-logo.png&thumb=200x100
the new URL would behttp://magickly.afeld.me/q/src/http%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fthumb%2F0%2F0d%2FImagemagick-logo.png%2F200px-Imagemagick-logo.png/thumb/200x100
## Encoded Syntax
Sometimes, you just can't handle escaped entities in your URLs (Facebook's handling of OpenGraph tags, for example). In those cases, we provide a Base64 encoded syntax which is an extension of the path-based Alternate Syntax above. Once your path-based url is constructed (see "Alternate Syntax" above), simply pass everything after the `q/` through Base64.urlsafe_encode or the javascript btoa() function and send it to the `qe/` endpoint instead.
Therefore, instead of
http://magickly.afeld.me/q/src/http%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fthumb%2F0%2F0d%2FImagemagick-logo.png%2F200px-Imagemagick-logo.png/thumb/200x100
the new URL would be
http://magickly.afeld.me/qe/c3JjL2h0dHAlM0ElMkYlMkZ1cGxvYWQud2lraW1lZGlhLm9yZyUyRndpa2lwZWRpYSUyRmNvbW1vbnMlMkZ0aHVtYiUyRjAlMkYwZCUyRkltYWdlbWFnaWNrLWxvZ28ucG5nJTJGMjAwcHgtSW1hZ2VtYWdpY2stbG9nby5wbmcvdGh1bWIvMjAweDEwMA==
## Analyzers
Magickly v1.2.0 introduces the ability to retrieve image properties via a REST API. For example, to retrieve the number of colors in the photo, visit:
[magickly.afeld.me/analyze/number_of_colors?src=...](http://magickly.afeld.me/analyze/number_of_colors?src=http://upload.wikimedia.org/wikipedia/commons/0/0d/Imagemagick-logo.png)
To get the list of available analyzers, visit [magickly.afeld.me/analyze](http://magickly.afeld.me/analyze)
## Customization
In addition to the available parameters listed above, custom "shortcuts" can be created to perform arbitrary imagemagick operations. For example, to create a shortcut called `resize_with_blur`:
# somewhere in your app configuration, i.e. config/initializers/magickly.rb for a Rails 3 app
Magickly.dragonfly.configure do |c|
c.job :resize_with_blur do |size|
process :convert, "-filter Gaussian -resize #{size}"
end
endwhich can then be used with the query string `?src=...&resize_with_blur=200x`. Note that magickly will pass the value of the query param to the block as a single string.
See the [Dragonfly documentation](http://markevans.github.com/dragonfly/file.GeneralUsage.html#Shortcuts) for more info on "shortcuts", and the [shortcuts.rb](https://github.com/afeld/magickly/blob/master/lib/shortcuts.rb) file for examples.
## Disclaimer
The hosted version of the app ([magickly.afeld.me](http://magickly.afeld.me)) is a single app instance intended for demonstration purposes - if you are going to be making a large number of API calls to it or would like to use it in production, please let us know :-)
## See Also
* [Thumbor](http://thumbor.org/)