skeptick 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +584 -0
- data/Rakefile +10 -0
- data/foo.rb +1 -0
- data/lib/skeptick.rb +2 -0
- data/lib/skeptick/chain.rb +55 -0
- data/lib/skeptick/chain/dsl_context.rb +21 -0
- data/lib/skeptick/command.rb +46 -0
- data/lib/skeptick/convert.rb +109 -0
- data/lib/skeptick/convert/dsl_context.rb +27 -0
- data/lib/skeptick/core.rb +46 -0
- data/lib/skeptick/error.rb +4 -0
- data/lib/skeptick/helper.rb +26 -0
- data/lib/skeptick/image.rb +69 -0
- data/lib/skeptick/image/dsl_context.rb +29 -0
- data/lib/skeptick/railtie.rb +8 -0
- data/lib/skeptick/sugar.rb +8 -0
- data/lib/skeptick/sugar/composition.rb +55 -0
- data/lib/skeptick/sugar/debugging.rb +12 -0
- data/lib/skeptick/sugar/drawing.rb +32 -0
- data/lib/skeptick/sugar/edges.rb +70 -0
- data/lib/skeptick/sugar/formatting.rb +12 -0
- data/lib/skeptick/sugar/geometry.rb +38 -0
- data/lib/skeptick/sugar/resizing.rb +16 -0
- data/lib/skeptick/sugar/sequence_manipulation.rb +43 -0
- data/lib/skeptick/version.rb +3 -0
- data/logo.png +0 -0
- data/logo.rb +45 -0
- data/refresh_preview.scpt +2 -0
- data/skeptick.gemspec +21 -0
- data/test/chain_test.rb +94 -0
- data/test/convert_test.rb +177 -0
- data/test/image_test.rb +145 -0
- data/test/sugar/composition_test.rb +273 -0
- data/test/sugar/debugging_test.rb +24 -0
- data/test/sugar/drawing_test.rb +86 -0
- data/test/sugar/edges_test.rb +99 -0
- data/test/sugar/formatting_test.rb +19 -0
- data/test/sugar/geometry_test.rb +92 -0
- data/test/sugar/resizing_test.rb +25 -0
- data/test/sugar/sequence_manipulation_test.rb +98 -0
- data/test/test_helper.rb +11 -0
- metadata +117 -0
@@ -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,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
|
data/logo.png
ADDED
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"
|
data/skeptick.gemspec
ADDED
@@ -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
|
data/test/chain_test.rb
ADDED
@@ -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
|