skeptick 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/.gitignore +18 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +584 -0
  5. data/Rakefile +10 -0
  6. data/foo.rb +1 -0
  7. data/lib/skeptick.rb +2 -0
  8. data/lib/skeptick/chain.rb +55 -0
  9. data/lib/skeptick/chain/dsl_context.rb +21 -0
  10. data/lib/skeptick/command.rb +46 -0
  11. data/lib/skeptick/convert.rb +109 -0
  12. data/lib/skeptick/convert/dsl_context.rb +27 -0
  13. data/lib/skeptick/core.rb +46 -0
  14. data/lib/skeptick/error.rb +4 -0
  15. data/lib/skeptick/helper.rb +26 -0
  16. data/lib/skeptick/image.rb +69 -0
  17. data/lib/skeptick/image/dsl_context.rb +29 -0
  18. data/lib/skeptick/railtie.rb +8 -0
  19. data/lib/skeptick/sugar.rb +8 -0
  20. data/lib/skeptick/sugar/composition.rb +55 -0
  21. data/lib/skeptick/sugar/debugging.rb +12 -0
  22. data/lib/skeptick/sugar/drawing.rb +32 -0
  23. data/lib/skeptick/sugar/edges.rb +70 -0
  24. data/lib/skeptick/sugar/formatting.rb +12 -0
  25. data/lib/skeptick/sugar/geometry.rb +38 -0
  26. data/lib/skeptick/sugar/resizing.rb +16 -0
  27. data/lib/skeptick/sugar/sequence_manipulation.rb +43 -0
  28. data/lib/skeptick/version.rb +3 -0
  29. data/logo.png +0 -0
  30. data/logo.rb +45 -0
  31. data/refresh_preview.scpt +2 -0
  32. data/skeptick.gemspec +21 -0
  33. data/test/chain_test.rb +94 -0
  34. data/test/convert_test.rb +177 -0
  35. data/test/image_test.rb +145 -0
  36. data/test/sugar/composition_test.rb +273 -0
  37. data/test/sugar/debugging_test.rb +24 -0
  38. data/test/sugar/drawing_test.rb +86 -0
  39. data/test/sugar/edges_test.rb +99 -0
  40. data/test/sugar/formatting_test.rb +19 -0
  41. data/test/sugar/geometry_test.rb +92 -0
  42. data/test/sugar/resizing_test.rb +25 -0
  43. data/test/sugar/sequence_manipulation_test.rb +98 -0
  44. data/test/test_helper.rb +11 -0
  45. metadata +117 -0
@@ -0,0 +1,8 @@
1
+ module Skeptick
2
+ class Railtie < Rails::Railtie
3
+ initializer "skeptick.configure_rails_initialization" do
4
+ Skeptick.logger = Rails.logger
5
+ Skeptick.cd_path = Rails.root
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require 'skeptick/sugar/composition'
2
+ require 'skeptick/sugar/debugging'
3
+ require 'skeptick/sugar/drawing'
4
+ require 'skeptick/sugar/geometry'
5
+ require 'skeptick/sugar/resizing'
6
+ require 'skeptick/sugar/sequence_manipulation'
7
+ require 'skeptick/sugar/formatting'
8
+ require 'skeptick/sugar/edges'
@@ -0,0 +1,55 @@
1
+ module Skeptick
2
+ module Sugar
3
+ module Composition
4
+ module Helper
5
+ def compose(blending, *args, &blk)
6
+ convert(*args, &blk).tap do |c|
7
+ c.append :compose, blending.to_s
8
+ c.append :composite
9
+ end
10
+ end
11
+ end
12
+
13
+ module Operators
14
+ def +(other)
15
+ compose(:over, self, other)
16
+ end
17
+
18
+ def -(other)
19
+ compose(:dstout, self, other)
20
+ end
21
+
22
+ def *(other)
23
+ compose(:multiply, self, other)
24
+ end
25
+
26
+ def /(other)
27
+ compose(:divide, self, other)
28
+ end
29
+
30
+ def &(other)
31
+ compose(:dstin, self, other) { apply '-alpha Set' }
32
+ end
33
+
34
+ def |(other)
35
+ compose(:dstover, self, other)
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ # Include compose into external context
42
+ include Sugar::Composition::Helper
43
+
44
+ # Include compose into Image's and Convert's DSL context
45
+ class Image::DslContext; include Sugar::Composition::Helper end
46
+ class Convert::DslContext; include Sugar::Composition::Helper end
47
+
48
+ # Include compose into Image and Convert objects
49
+ class Image; include Sugar::Composition::Helper end
50
+ class Convert; include Sugar::Composition::Helper end
51
+
52
+ # Include operators into Image and Convert objects
53
+ class Image; include Sugar::Composition::Operators end
54
+ class Convert; include Sugar::Composition::Operators end
55
+ end
@@ -0,0 +1,12 @@
1
+ module Skeptick
2
+ module Sugar
3
+ module Debugging
4
+ def save(path)
5
+ apply('-write', path)
6
+ end
7
+ end
8
+ end
9
+
10
+ class Image::DslContext; include Sugar::Debugging end
11
+ class Convert::DslContext; include Sugar::Debugging end
12
+ end
@@ -0,0 +1,32 @@
1
+ module Skeptick
2
+ module Sugar
3
+ module Drawing
4
+ def canvas(string, options = {})
5
+ if options[:size]
6
+ set '-size', options[:size]
7
+ end
8
+
9
+ set "canvas:#{string}"
10
+ end
11
+
12
+ def draw(*args)
13
+ set '-draw', args.join(' ').shellescape
14
+ end
15
+
16
+ def write(text, options = {})
17
+ if options[:left] && options[:top]
18
+ opts = "#{options[:left]},#{options[:top]} "
19
+ end
20
+
21
+ draw "text #{opts}'#{text}'"
22
+ end
23
+
24
+ def font(name)
25
+ set '-font', name.split(/\s/).map(&:capitalize).join('-')
26
+ end
27
+ end
28
+ end
29
+
30
+ class Image::DslContext; include Sugar::Drawing end
31
+ class Convert::DslContext; include Sugar::Drawing end
32
+ end
@@ -0,0 +1,70 @@
1
+ require 'skeptick/sugar/composition'
2
+ require 'skeptick/sugar/formatting'
3
+
4
+ module Skeptick
5
+ module Sugar
6
+ module Edges
7
+ def rounded_corners_image(image = nil, options = {}, &blk)
8
+ options = image.is_a?(Hash) ? image : options
9
+ radius = options[:radius] || 15
10
+ width, height = options.values_at(:width, :height)
11
+
12
+ if options[:size]
13
+ width, height = *options[:size].split('x').map(&:to_i)
14
+ end
15
+
16
+ if block_given?
17
+ image = Image.new(self, &blk)
18
+ end
19
+
20
+ border = if width && height
21
+ "roundrectangle 1,1 #{width},#{height} #{radius},#{radius}"
22
+ else
23
+ convert(image, to: 'info:') do
24
+ format "roundrectangle 1,1 %[fx:w], %[fx:h] #{radius},#{radius}"
25
+ end.execute.strip
26
+ end
27
+
28
+ compose(:dstin, image) do
29
+ convert do
30
+ set '+clone'
31
+ set :alpha, 'transparent', :background, 'none'
32
+ draw border
33
+ end
34
+
35
+ set :alpha, 'set'
36
+ end
37
+ end
38
+
39
+ def torn_paper_image(image = nil, options = {}, &blk)
40
+ options = image.is_a?(Hash) ? image : options
41
+
42
+ spread = options[:spread] || 1
43
+ blur = options[:blur] || '0x.7'
44
+ threshold = options[:threshold] || 50
45
+
46
+ if block_given?
47
+ image = Image.new(self, &blk)
48
+ end
49
+
50
+ compose(:copy_opacity, image) do
51
+ convert do
52
+ set '+clone'
53
+ apply :alpha, 'extract'
54
+ apply '-virtual-pixel', 'black'
55
+ apply :spread, spread
56
+ apply :blur, blur
57
+ apply :threshold, "#{threshold}%"
58
+ end
59
+
60
+ apply :alpha, 'off'
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ include Sugar::Edges
67
+
68
+ class Image::DslContext; include Sugar::Edges end
69
+ class Convert::DslContext; include Sugar::Edges end
70
+ end
@@ -0,0 +1,12 @@
1
+ module Skeptick
2
+ module Sugar
3
+ module Formatting
4
+ def format(*args)
5
+ set '-format', args.join(' ').shellescape
6
+ end
7
+ end
8
+ end
9
+
10
+ class Image::DslContext; include Sugar::Formatting end
11
+ class Convert::DslContext; include Sugar::Formatting end
12
+ end
@@ -0,0 +1,38 @@
1
+ module Skeptick
2
+ module Sugar
3
+ module Geometry
4
+ def geometry(options = {})
5
+ result = ''
6
+
7
+ result << if options[:size]
8
+ options[:size]
9
+ else
10
+ if options[:width] && options[:height]
11
+ "#{options[:width]}x#{options[:height]}"
12
+ elsif options[:width]
13
+ "#{options[:width]}x"
14
+ elsif options[:height]
15
+ "x#{options[:height]}"
16
+ else
17
+ ''
18
+ end
19
+ end
20
+
21
+ if options[:left] || options[:top]
22
+ left = '%+d' % (options[:left] || 0)
23
+ top = '%+d' % (options[:top] || 0)
24
+ result << "#{left}#{top}"
25
+ end
26
+
27
+ result << '%' if options[:percentage]
28
+ result << '!' if options[:exact]
29
+ result << '<' if options[:expand_only]
30
+ result << '>' if options[:shrink_only]
31
+
32
+ result
33
+ end
34
+ end
35
+ end
36
+
37
+ include Sugar::Geometry
38
+ end
@@ -0,0 +1,16 @@
1
+ require 'skeptick/sugar/geometry'
2
+
3
+ module Skeptick
4
+ module Sugar
5
+ module Resizing
6
+ def resized_image(path, options = {})
7
+ image("#{path}[#{geometry(options)}]")
8
+ end
9
+ end
10
+ end
11
+
12
+ include Sugar::Resizing
13
+
14
+ class Image::DslContext; include Sugar::Resizing end
15
+ class Convert::DslContext; include Sugar::Resizing end
16
+ end
@@ -0,0 +1,43 @@
1
+ module Skeptick
2
+ module Sugar
3
+ module SequenceManipulation
4
+ def clone(*args)
5
+ obj = (args.size < 2 ? args.first : args)
6
+ set(
7
+ if obj
8
+ "-clone #{Helper.object_to_index_range_list(obj)}"
9
+ else
10
+ '+clone'
11
+ end
12
+ )
13
+ end
14
+
15
+ def delete(*args)
16
+ obj = (args.size < 2 ? args.first : args)
17
+ set(
18
+ if obj
19
+ "-delete #{Helper.object_to_index_range_list(obj)}"
20
+ else
21
+ '+delete'
22
+ end
23
+ )
24
+ end
25
+
26
+ def swap(*args)
27
+ set(
28
+ if args.empty?
29
+ '+swap'
30
+ elsif args.size == 2
31
+ "-swap #{args.join(',')}"
32
+ else
33
+ raise ArgumentError,
34
+ "wrong number of arguments (#{args.size} for 0, 2)"
35
+ end
36
+ )
37
+ end
38
+ end
39
+ end
40
+
41
+ class Image::DslContext; include Sugar::SequenceManipulation end
42
+ class Convert::DslContext; include Sugar::SequenceManipulation end
43
+ end
@@ -0,0 +1,3 @@
1
+ module Skeptick
2
+ VERSION = "0.1.0"
3
+ end
Binary file
data/logo.rb ADDED
@@ -0,0 +1,45 @@
1
+ require_relative 'lib/skeptick'
2
+
3
+ include Skeptick
4
+
5
+ image_size = '400x120'
6
+
7
+ paper = rounded_corners_image(size: image_size, radius: 25) do
8
+ set :size, image_size
9
+ image 'tile:granite:'
10
+ apply '-brightness-contrast', '38x-33'
11
+ apply :blur, '0x0.5'
12
+ end
13
+
14
+ left, top = 8, 80
15
+ text = image do
16
+ canvas :none, size: '395x110'
17
+ font 'Handwriting - Dakota Regular'
18
+ set :pointsize, 90
19
+ set :fill, 'gradient:#37e-#007'
20
+ write 'Skeptick', left: left, top: top
21
+ apply :blur, '0x0.7'
22
+ end
23
+
24
+ bezier = \
25
+ "#{left + 17 }, #{top + 17} #{left + 457}, #{top - 13} " +
26
+ "#{left + 377}, #{top + 27} #{left + 267}, #{top + 27}"
27
+
28
+ curve = image do
29
+ canvas :none, size: '395x110'
30
+ set :strokewidth, 2
31
+ set :stroke, 'gradient:#37e-#007'
32
+ draw "fill none bezier #{bezier}"
33
+ end
34
+
35
+ result_path = "#{File.dirname(__FILE__)}/logo.png"
36
+
37
+ torn = torn_paper_image(
38
+ paper * (text + curve),
39
+ spread: 50,
40
+ blur: '3x10'
41
+ )
42
+
43
+ logo = convert(torn, to: result_path)
44
+ logo.build
45
+ # system "osascript refresh_preview.scpt"
@@ -0,0 +1,2 @@
1
+ tell application "Preview" to activate
2
+ tell application "Sublime Text 2" to activate
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'skeptick/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "skeptick"
8
+ gem.version = Skeptick::VERSION
9
+ gem.authors = ["Maxim Chernyak"]
10
+ gem.email = ["max@bitsonnet.com"]
11
+ gem.description = %q{Thin ImageMagick DSL with smart command composition}
12
+ gem.summary = %q{Skeptick doesn't believe in Magick}
13
+ gem.homepage = "https://github.com/maxim/skeptick"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency 'posix-spawn', '~> 0.3.6'
21
+ end
@@ -0,0 +1,94 @@
1
+ require_relative 'test_helper'
2
+
3
+ class ChainTest < Skeptick::TestCase
4
+ include Skeptick
5
+
6
+ def test_dsl_methods_available
7
+ assert_respond_to self, :chain
8
+ end
9
+
10
+ def test_chaining_two_converts
11
+ cmd = chain do
12
+ convert('foo')
13
+ convert(:pipe)
14
+ end
15
+
16
+ assert_equal 'convert foo miff:- | convert miff:- miff:-', cmd.to_s
17
+ end
18
+
19
+ def test_chaining_two_converts_to_destination
20
+ cmd = chain(to: 'baz') do
21
+ convert('foo')
22
+ convert(:pipe)
23
+ end
24
+
25
+ assert_equal 'convert foo miff:- | convert miff:- baz', cmd.to_s
26
+ end
27
+
28
+ def test_last_convert_destination_prevails
29
+ cmd = chain(to: 'baz') do
30
+ convert('foo')
31
+ convert(:pipe, to: 'qux')
32
+ end
33
+
34
+ assert_equal 'convert foo miff:- | convert miff:- qux', cmd.to_s
35
+ end
36
+
37
+ def test_pipe_or_returns_pipe_if_piping
38
+ cmd = chain do
39
+ convert('foo')
40
+ convert(pipe_or('bar'))
41
+ end
42
+
43
+ assert_equal 'convert foo miff:- | convert miff:- miff:-', cmd.to_s
44
+ end
45
+
46
+ def test_pipe_or_returns_path_if_not_piping
47
+ cmd = chain { convert(pipe_or('foo')) }
48
+ assert_equal 'convert foo miff:-', cmd.to_s
49
+ end
50
+
51
+ def test_lvars_from_external_context_are_accessible
52
+ foo = 'foo'
53
+ cmd = chain { convert(foo) }
54
+ assert_equal 'convert foo miff:-', cmd.to_s
55
+ end
56
+
57
+ def test_methods_from_external_context_are_accessible
58
+ context = Class.new do
59
+ include Skeptick
60
+ def foo; 'foo' end
61
+ def cmd; chain { convert(foo) } end
62
+ end
63
+
64
+ assert_equal 'convert foo miff:-', context.new.cmd.to_s
65
+ end
66
+
67
+ def test_complex_piping_case
68
+ cmd = chain(to: 'foo') do
69
+ convert('resized_design', 'mask') do
70
+ set '-geometry', '-left-top'
71
+ set '-brightness-contrast', '-12x20'
72
+ end
73
+
74
+ convert('foo') do
75
+ convert('qux') do
76
+ set '+asdf'
77
+ set '+fdsa'
78
+ end
79
+
80
+ image 'bleh'
81
+ set '-resize'
82
+ end
83
+
84
+ convert('paper_path', pipe_or('paper_path')) do
85
+ set '-geometry +left+top'
86
+ end
87
+ end
88
+
89
+ assert_equal 'convert resized_design mask -geometry -left-top ' +
90
+ '-brightness-contrast -12x20 miff:- | convert foo ' +
91
+ '\( qux \+asdf \+fdsa \) bleh -resize miff:- | convert paper_path ' +
92
+ 'miff:- -geometry \+left\+top foo', cmd.to_s
93
+ end
94
+ end