{"id":13484163,"url":"https://github.com/maxim/skeptick","last_synced_at":"2025-04-04T12:09:26.009Z","repository":{"id":5937395,"uuid":"7157683","full_name":"maxim/skeptick","owner":"maxim","description":"Better ImageMagick for Ruby","archived":false,"fork":false,"pushed_at":"2015-03-17T16:13:29.000Z","size":567,"stargazers_count":317,"open_issues_count":1,"forks_count":7,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-03-28T11:11:13.287Z","etag":null,"topics":["image-processing","imagemagick","ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maxim.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-12-14T00:15:57.000Z","updated_at":"2024-08-26T16:24:57.000Z","dependencies_parsed_at":"2022-09-11T08:22:11.117Z","dependency_job_id":null,"html_url":"https://github.com/maxim/skeptick","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxim%2Fskeptick","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxim%2Fskeptick/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxim%2Fskeptick/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxim%2Fskeptick/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maxim","download_url":"https://codeload.github.com/maxim/skeptick/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247174454,"owners_count":20896078,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["image-processing","imagemagick","ruby"],"created_at":"2024-07-31T17:01:20.105Z","updated_at":"2025-04-04T12:09:25.990Z","avatar_url":"https://github.com/maxim.png","language":"Ruby","readme":"# Skeptick: Better ImageMagick for Ruby\n\n[![Build Status](https://travis-ci.org/maxim/skeptick.png?branch=master)](https://travis-ci.org/maxim/skeptick)\n[![Code Climate](https://codeclimate.com/github/maxim/skeptick.png)](https://codeclimate.com/github/maxim/skeptick)\n[![Dependency Status](https://gemnasium.com/maxim/skeptick.png)](https://gemnasium.com/maxim/skeptick)\n\nSkeptick is an all-purpose DSL for building and running ImageMagick commands.\nIt helps you build any transformations, from trivial resizes to complex mask\nalgorithms and free drawing. In a nutshell, Skeptick is nothing more than a\nstring manipulator and a process spawner. That's all it's meant to be. However,\nwith Skeptick you get quite a few advantages over using plain shell-out or other\nlibraries.\n\n## What you get\n\n* Clean Ruby syntax to build ImageMagick commands\n* Composable Image objects\n* ImageMagick's `STDERR` output revealed in a Ruby exception\n* Ability to save intermediate images for debugging\n* Minimal memory consumption on shell-outs thanks to\n[posix-spawn](https://github.com/rtomayko/posix-spawn)\n* Emphasis on performing the whole transformation in a single command\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n    gem 'skeptick'\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install skeptick\n\n## Usage\n\nTo use Skeptick, you simply require it and include the module into your class.\n\n```ruby\nrequire 'skeptick'\n\nclass MyClass\n  include Skeptick\n\n  def convert_some_image\n    cmd = convert(to: 'result.png') do\n      # ...\n    end\n\n    cmd.run\n  end\nend\n```\n\nThe `cmd` object seen in above example can be inspected to see the exact command\nthat Skeptick will run. Simply use `cmd.inspect` or `cmd.to_s`. Skeptick never\nruns anything until you call `run` (except for one very special case), so you\ncan inspect commands all you want before executing them.\n\nIf you don't want to require all of Skeptick, you can just require the core, and\nand select any specific sugar you want.\n\n```ruby\nrequire 'skeptick/core'\nrequire 'skeptick/sugar/resized_image'\nrequire 'skeptick/sugar/compose'\n```\n\nSee the `lib/skeptick/sugar` dir for all the goodies.\n\nIn Rails Skeptick will automatically use `Rails.logger` and `Rails.root` as\n`cd_path`. You can also configure your own.\n\n```ruby\nSkeptick.logger  = MyLogger.new\nSkeptick.cd_path = '/some/dir'\n```\n\nYou can enable `debug_mode` to display every executed command in the log.\n\n```ruby\nSkeptick.debug_mode = true\n```\n\n## Security Note\n\n*Never* insert any user input into any of Skeptick's commands. This should be\nobvious. Skeptick executes strings in your shell.\n\n## DSL\n\n![Skeptick Logo](https://raw.github.com/maxim/skeptick/master/logo.png)\n\nTake a look at [logo.rb](logo.rb) to see thow this logo was generated.\n\nA lot is going on in the above script, no worries, it's just a showcase. I bet\nthe first thing you noticed is a shitstorm of little method names like `canvas`,\n`font`, `write`, `draw`, etc. Well, they are all sugar. We will cover sugar\nbelow.\n\nThere are actually only 2 useful methods in all of Skeptick: `convert` and\n`set`.\n\n### Convert\n\n`convert` can be used both standalone and inside another `convert`. You could\nsay this.\n\n```ruby\ncommand = convert('image1.png', to: 'image2.png') do\n  set :resize, '200x200'\nend\n\n# OUTPUT:\n# convert image1.png -resize 200x200 image2.png\n```\n\nOr you could put it inside, and it will become a parenthesized subcommand.\n\n```ruby\ncommand = convert('image1.png', to: 'image2.png') do\n  convert do\n    set '+clone'           # pull in image1 into parentheses\n    set :resize, '100x100' # resize image1's clone in memory\n  end\n\n  set '-compose', 'over'\n  set '-composite'\nend\n\n# OUTPUT:\n# convert image1.png ( +clone -resize 100x100 )\n#   -compose over -composite image2.png\n```\n\nIf you love parentheses a lot, you could nest `convert` infinitely. However,\nImageMagick's `clone`, `delete`, and `swap` are your friends, learn them to\ncure parenthethitis.\n\nOh, speaking of nesting — we can reuse that whole command inside another command\nby passing it to `convert` in place of an image filepath.\n\n```ruby\nnew_command = convert(command, to: 'whatever.png') do\n  set '-resize', '300x300'\nend\n\n# OUTPUT:\n# convert\n#   ( image1.png ( +clone -resize 100x100 ) -compose over -composite )\n#   -resize 300x300 whatever.png\n```\n\nSee what I did there? The `command` from previous snippet is passed into\n`convert`. If you have a `convert` object in a variable, you can use it inside\nanother `convert` object down the line. Nesting possibilities are endless.\n\nThe same snippet could also be written like this.\n```ruby\nnew_command = convert(to: 'whatever.png') do\n  image command\n  set :resize, '300x300'\nend\n```\n\n2 differences: 1 - instead of passing in `command` as argument we declare it\ninside the block. 2 - resize is a symbol. Any symbol passed into `set`\nautomatically becomes a string with dash in front of it. Speaking of set.\n\n### Set\n\n`set` adds stuff to your command. You can give it any various arguments, it\ndoesn't care.\n\n```ruby\n# Works the same way:\nset '-resize', '100x100'\nset :resize, '100x100'\n\n# bad, won't work\nset '-resize 100x100'\n```\n\nWatch 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.`\n\nIn addition to `set` there are also `prepend` and `append` to put stuff at the\nbeginning or end of a command, but they are rarely useful, and mostly for\nimplementing your own sugar.\n\n## Sugar\n\nSkeptick comes with a bunch of sugar. When you require Skeptick, you can simply\nrequire everything. This includes all the sugar functionality.\n\n```ruby\nrequire 'skeptick'\n```\n\nHowever, you can require just the core stuff described above, and select any\nsugar you want.\n\n```ruby\nrequire 'skeptick/core'\nrequire 'skeptick/sugar/compose'\n```\n\n### Compose Sugar\n\nCompose is sugar that adds `compose` shortcut to Skeptick's DSL.\n\n```ruby\ncommand = compose(:multiply, 'a.png', 'b.png', to: 'out.png') do\n  set :resize, '200x200'\nend\n\n# OUTPUT:\n# convert a.png b.png -compose multiply -resize 200x200 -composite out.png\n```\n\nIt takes the blending type as the first argument, and injects some extra stuff\ninto the resulting command.\n\nAs with `convert`, you don't have to list your images as method arguments.\nInstead you could declare them inside the block using the `image` method. The\nfollowing command does the same thing.\n\n```ruby\ncommand = compose(:multiply, to: 'out.png') do\n  image 'a.png'\n  convert 'b.png'\n  set :resize, '200x200'\nend\n```\n\n*Note:* `image` is alias of `convert`.\n\nSince most of Skeptick's power comes from the ability to infinitely nest things,\nhere's an example involving a nested `compose`.\n\n```ruby\ncommand = convert('image1.png', to: 'result.png') do\n  compose(:multiply) do\n    image 'image2.png[200x200]'\n\n    convert 'image3.png' do\n      set :unsharp, '0x5'\n    end\n  end\nend\n\n# OUTPUT:\n# convert\n#   image1.png image2.png[200x200] ( image3.png -unsharp 0x5 ) -compose\n#   multiply -composite result.png\"\n```\n\nNotice how we nest `compose` inside of `convert`, and then `convert` inside of\n`compose`.\n\n### Compose Operators\n\nThis is more of a gimmick than a real feature, but you can use math operators\nlike `+`, `-`, `*`, `/`, `\u0026`, `|` to compose images. These are all based on\n`compose` method. Here's a multiply example.\n\n```ruby\nimage1 = image('foo.png')\nimage2 = image('bar.png')\nresult = convert(image1 * image2, to: 'baz.png')\n\n# OUTPUT:\n# convert foo.png bar.png -compose multiply -composite baz.png\n```\n\nAs you can see, this is equivalent of simply using `compose`.\n\n```ruby\n# Same thing\nresult = compose(:multiply, 'foo.png', 'bar.png', to: 'baz.png')\n```\n\nCheck out [lib/skeptick/sugar/compose.rb](lib/skeptick/sugar/compose.rb) for\nwhat these operators do.\n\n### clone, delete, swap\n\nSkeptick provides methods `clone`, `delete`, and `swap` to\nmanipulate declared images in a sequence, just like in ImageMagick CLI.\n\n```ruby\ncommand = compose(:over, 'image1.png', to: 'result.png') do\n  # You could think of image sequence as a ruby array. Here's what it would\n  # look like right now.\n  # [ 'image1.png' ]\n\n  compose(:multiply) do\n    image 'mask.png' # loading another image for this operation\n    clone(0)         # cloning image1.png from outside \"into parentheses\"\n  end\n\n  # Sequence at this point:\n  # [ 'image1.png', 'result of compose(:multiply)' ]\n\n  delete(0) # deleting image1.png from the sequence and from memory\n\n  # Sequence at this point:\n  # [ 'result of compose(:multiply)' ]\n\n  # At this point the only image loaded in memory is the one produced by the\n  # compose(:multiply) command above. Let's load another one.\n\n  image 'image2.png'\n\n  # Sequence at this point:\n  # [ 'result of compose(:multiply)', 'image2.png' ]\n\n  # Now we have two images in the sequence. We can swap them in case we need\n  # to change their order.\n\n  swap\n\n  # Sequence at this point:\n  # [ 'image2.png', 'result of compose(:multiply)' ]\n\n  # Now image2.png is first in the sequence, and the output of\n  # compose(:multiply) is second. Since our outermost command is compose(:over),\n  # at this point these 2 images will be composed over each other, and the\n  # result written to result.png.\nend\n\n# OUTPUT\n# convert\n#  image1.png ( mask.png -clone 0 -compose multiply -composite )\n#  -delete 0 image2.png +swap -compose over -composite result.png\n```\n\nYou can use `clone` and `delete` to refer to multiple images at once by passing\nmutliple indexes as arguments, like `clone(0,1,2)` or `delete(0,1)`. Ranges are\nalso accepted. Without any arguments `clone` and `delete` are translated to\nImageMagick's `+clone` and `+delete`. They then refer to the last image in the\nsequence. Same with `swap` - you can provide two indexes in arguments like\n`swap(1,3)` to swap any 2 images in the sequence, or without arguments it'll\nact as `+swap` - which swaps last two images.\n\n### Write\n\nSometimes you might want to take a look at an intermediate image that's being\ngenerated inside parentheses, nested somewhere in your command. You can do so\nwith the help of `write '/path/to/img.png'`, which is defined in\n`skeptick/sugar/write.rb`.\n\n```ruby\ncommand = convert(to: 'result.png') do\n  compose(:multiply, 'a.png', 'b.png') do\n    write '~/Desktop/debug.png'\n  end\n\n  set :resize, '200x200'\nend\n```\n\nIn this case the result of inner `compose` command will be saved to desktop\nwithout affecting anything else. This is a feature that already exists in\nImageMagick, as you can see for yourself from generated command:\n\n    convert\n      ( a.png b.png -compose multiply -composite -write ~/Desktop/debug.png )\n      -resize 200x200 result.png\n\nDocumentation is to be continued...\n\n## Contributing\n\n1. Fork it\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create new Pull Request\n","funding_links":[],"categories":["Ruby","Image Processing"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxim%2Fskeptick","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaxim%2Fskeptick","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxim%2Fskeptick/lists"}