compass-magick 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,40 @@
1
+ module Compass::Magick
2
+ module Types
3
+ # A type that generates a {Canvas} from a region filled with a solid
4
+ # color.
5
+ #
6
+ # @example
7
+ #
8
+ # Solid.new(Sass::Script::Color.new([255, 255, 255])).to_canvas(
9
+ # Sass::Script::Number(320),
10
+ # Sass::Script::Number(200)
11
+ # )
12
+ class Solid < Type
13
+ include Utils
14
+
15
+ # Initializes a new Solid instance.
16
+ #
17
+ # @param [Sass::Script::Color] color The solid background color.
18
+ def initialize(color)
19
+ assert_type 'color', color, Sass::Script::Color
20
+ @color = color
21
+ end
22
+
23
+ # @return [Sass::Script::Color] The solid background color.
24
+ attr_reader :color
25
+
26
+ def to_canvas(width, height)
27
+ assert_type 'width', width, Sass::Script::Number
28
+ assert_type 'height', height, Sass::Script::Number
29
+ color = to_chunky_color(@color)
30
+ canvas = Canvas.new(width, height)
31
+ (0...canvas.height).each do |y|
32
+ (0...canvas.width).each do |x|
33
+ canvas.set_pixel(x, y, color)
34
+ end
35
+ end
36
+ canvas
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,39 @@
1
+ module Compass::Magick
2
+ # Abstract Type class.
3
+ #
4
+ # Defines the methods all Type instances must implement.
5
+ #
6
+ # @abstract
7
+ # @see Compass::Magick::Types
8
+ class Type
9
+ include Scriptable
10
+
11
+ # Generates a {Canvas} object.
12
+ #
13
+ # @abstract
14
+ # @param [Sass::Script::Number] width The width of the Canvas.
15
+ # @param [Sass::Script::Number] height The height of the Canvas.
16
+ # @return [Canvas] The Canvas object which is composed
17
+ # on top of the original image.
18
+ def to_canvas(width, height)
19
+ raise AbstractMethod.new("#{self.class} must implement 'to_canvas'")
20
+ end
21
+ end
22
+
23
+ # The Types module includes all fill types available in Compass Magick.
24
+ #
25
+ # Types generate {Canvas} objects with the given options, e.g., a solid
26
+ # color or a linear gradient. The resulting Canvas is then composed on top
27
+ # of the original image using alpha blending.
28
+ #
29
+ # This can be a slow operation, but it reduces the amount of work required
30
+ # and abstracts the drawing logic in four easy steps - draw B/W shape, fill
31
+ # rectangle, mask and compose on top of original image.
32
+ #
33
+ # @see Compass::Magick::Types::Solid
34
+ # @see Compass::Magick::Types::Gradients
35
+ module Types; end
36
+ end
37
+
38
+ require 'magick/types/solid'
39
+ require 'magick/types/gradients'
@@ -0,0 +1,92 @@
1
+ module Compass::Magick
2
+ # Utilities methods used throughout Compass Magick.
3
+ module Utils
4
+ extend self
5
+
6
+ # Checks if <tt>arg</tt> is of the expected <tt>type</tt> and raises a
7
+ # {TypeMismatch} exception otherwise.
8
+ #
9
+ # @param [String] name The argument name (used in the exception message).
10
+ # @param [Object] arg The argument to validate.
11
+ # @param [Object] type The expected <tt>arg</tt> type.
12
+ def assert_type(name, arg, type)
13
+ raise TypeMismatch.new("(#{self.class}) Type mismatch for argument '#{name}'; " +
14
+ "expected #{type} got #{arg.class}(#{arg.inspect}) instead") unless
15
+ arg.nil? ||
16
+ arg.kind_of?(type)
17
+ end
18
+
19
+ # Checks if <tt>arg</tt> is a sub-class of any of the supported
20
+ # <tt>types</tt> and raises a {NotSupported} exception otherwise.
21
+ #
22
+ # @param [String] name The argument name or method signature (used in the
23
+ # exception message).
24
+ # @param [Object] arg The argument to validate.
25
+ # @param [Array<Object>] types The list of supported <tt>arg</tt> types.
26
+ def assert_one_of(name, arg, *types)
27
+ for type in types do
28
+ return if arg.kind_of?(type)
29
+ end
30
+ raise NotSupported.new("#{name} expected argument of type [#{types.join ', '}] got #{arg.class}(#{arg.inspect}) instead")
31
+ end
32
+
33
+ # Converts a Sass::Script::Color to ChunkyPNG::Color object.
34
+ #
35
+ # @param [Sass::Script::Color] color The source color in Sass' format.
36
+ # @return [ChunkyPNG::Color] The source color in ChunkyPNG's format.
37
+ def to_chunky_color(color)
38
+ ChunkyPNG::Color.rgba(color.red, color.green, color.blue, color.alpha * 255)
39
+ end
40
+
41
+ # Converts a fill type (solid color or gradient) to a {Canvas} object.
42
+ #
43
+ # @param [Object] type The type of fill type to convert. Supported:
44
+ # * Sass::Script::Color
45
+ # * Sass::Script::String
46
+ # * {Compass::Magick::Types::Solid}
47
+ # * {Compass::Magick::Types::Gradients::Linear}
48
+ # @param [Sass::Script::Number] width The width of the generated
49
+ # {Canvas}.
50
+ # @param [Sass::Script::Number] height The height of the generated
51
+ # {Canvas}.
52
+ # @return [Canvas] The canvas in the dimensions given with the fill
53
+ # type applied.
54
+ def to_canvas(type, width, height)
55
+ Compass::Magick::Utils.assert_one_of 'to_canvas(..)', type, Sass::Script::Color, Sass::Script::String, Compass::Magick::Type, ChunkyPNG::Canvas
56
+ if type.kind_of?(Sass::Script::Color)
57
+ Compass::Magick::Types::Solid.new(type).to_canvas(width, height)
58
+ elsif type.kind_of?(Sass::Script::String)
59
+ if type.value == 'transparent'
60
+ ChunkyPNG::Canvas.new(width.value, height.value, ChunkyPNG::Color.rgba(0, 0, 0, 0))
61
+ else
62
+ raise NotSupported.new("to_canvas(..) supports String argument of values ['transparent'] got '#{type}' instead")
63
+ end
64
+ elsif type.kind_of?(ChunkyPNG::Canvas)
65
+ type.tile(width.value, height.value)
66
+ elsif type.kind_of?(Compass::Magick::Types::Solid) || type.kind_of?(Compass::Magick::Types::Gradients::Linear)
67
+ type.to_canvas(width, height)
68
+ end
69
+ end
70
+
71
+ # Converts the Sass::Script::Number to a fixed value.
72
+ #
73
+ # @param [Sass::Script::Number] number The number to convert.
74
+ # @param [Float] max The maximum allowed value for this number.
75
+ # @param [Float] default The default value for this number.
76
+ # @return [Float]
77
+ # If <tt>number</tt> is <tt>nil</tt>, <tt>true</tt> or <tt>false</tt>, the <tt>default</tt> is returned.
78
+ # If <tt>number</tt>'s units are '%', it is calculated as a percentage of <tt>max</tt>.
79
+ # If the value is negative, it is calculated as an offset against <tt>max</tt>.
80
+ # Otherwise, the value is returned as-is.
81
+ def value_of(number, max, default = nil)
82
+ return default if number.nil? || (number.kind_of?(Sass::Script::Bool) && ! number.value)
83
+ assert_type 'number', number, Sass::Script::Number
84
+ return max * (number.value.to_f / 100) if number.unit_str == '%'
85
+ return max + number.value if number.value < 0
86
+ number.value
87
+ end
88
+
89
+ # A helper Point(x, y) structure.
90
+ class Point < Struct.new(:x, :y); end
91
+ end
92
+ end
data/lib/magick.rb ADDED
@@ -0,0 +1,79 @@
1
+ # Local development requires we have the current directory on $LOAD_PATH.
2
+ $: << File.dirname(__FILE__)
3
+
4
+ begin
5
+ require 'oily_png'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ begin
9
+ require 'oily_png'
10
+ rescue LoadError
11
+ puts '(Compass:Magick) Unable to load OilyPNG, reverting to ChunkyPNG.'
12
+ puts 'OilyPNG is a C extension to speed up the pure Ruby library.'
13
+ puts "Please install it with the following command:\n\n"
14
+ puts " gem install oily_png\n\n"
15
+ begin
16
+ require 'chunky_png'
17
+ rescue LoadError
18
+ puts "(Compass:Magick) Unable to load ChunkyPNG. Please install it with the following command:\n\n"
19
+ puts " gem install chunky_png\n\n"
20
+ raise
21
+ end
22
+ end
23
+ end
24
+
25
+ # Compass Magick, a library for dynamic image generation.
26
+ #
27
+ # The Compass::Magick module defines constants and exception used throughout
28
+ # the project.
29
+ #
30
+ # @author Stan Angeloff
31
+ module Compass::Magick
32
+ # The current version of Compass Magick. This value is updated manually on
33
+ # release. If you are using a Git clone, the version will always end with
34
+ # '.git'.
35
+ VERSION = '0.1.2.git'
36
+
37
+ # The locations where plug-ins are located. These paths are scanned for
38
+ # *.rb files and loaded in order.
39
+ PLUGINS_PATH = [
40
+ File.join(File.dirname(__FILE__), 'plugins'),
41
+ File.join(ENV['HOME'], '.magick', 'plugins'),
42
+ File.join(Dir.getwd, 'plugins')
43
+ ]
44
+
45
+ # Default exception class for Compass Magick
46
+ class Exception < ::StandardError; end
47
+
48
+ # Exception that is raised when an argument's type does not match the
49
+ # expected.
50
+ class TypeMismatch < Exception; end
51
+
52
+ # Exception that is raised when an abstract method is called.
53
+ class AbstractMethod < Exception; end
54
+
55
+ # Exception that is raised when a method is called with arguments it does
56
+ # not support.
57
+ class NotSupported < Exception; end
58
+
59
+ # Exception that is raised when a method is called in a context it does not
60
+ # support.
61
+ class NotAllowed < Exception; end
62
+ end
63
+
64
+ require 'magick/utils'
65
+ require 'magick/scriptable'
66
+ require 'magick/command'
67
+ require 'magick/effect'
68
+ require 'magick/canvas'
69
+ require 'magick/shapes'
70
+ require 'magick/types'
71
+ require 'magick/functions'
72
+
73
+ # Register Compass Magick as a Compass framework.
74
+ #
75
+ # @see http://compass-style.org/docs/tutorials/extensions/
76
+ Compass::Frameworks.register('magick',
77
+ :stylesheets_directory => File.join(File.dirname(__FILE__), 'stylesheets'),
78
+ :templates_directory => File.join(File.dirname(__FILE__), 'templates')
79
+ )
@@ -0,0 +1,29 @@
1
+ module Compass::Magick
2
+ module Plugins
3
+ # Applies rounded corners around the {Canvas}.
4
+ #
5
+ # @param [Sass::Script::Number] radius The corner radius.
6
+ # @param [Sass::Script::Bool] top_left Controls the top-left corner
7
+ # radius effect (default <tt>true</tt>)
8
+ # @param [Sass::Script::Bool] top_right Controls the top-right corner
9
+ # radius effect (default <tt>true</tt>)
10
+ # @param [Sass::Script::Bool] bottom_right Controls the bottom-right
11
+ # corner radius effect (default <tt>true</tt>)
12
+ # @param [Sass::Script::Bool] bottom_left Controls the bottom-left
13
+ # corner radius effect (default <tt>true</tt>)
14
+ # @return {Command} A command(-set) which applies the corners on the
15
+ # canvas.
16
+ def magick_corners(radius, top_left = nil, top_right = nil, bottom_right = nil, bottom_left = nil)
17
+ Command.new do |canvas|
18
+ Canvas.new(canvas, magick_mask(
19
+ magick_canvas(
20
+ Sass::Script::Number.new(canvas.width),
21
+ Sass::Script::Number.new(canvas.height),
22
+ magick_fill(Sass::Script::Color.new([0, 0, 0])),
23
+ magick_border(Sass::Script::Color.new([255, 255, 255]), radius, nil, top_left, top_right, bottom_right, bottom_left)
24
+ )
25
+ ))
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,49 @@
1
+ module Compass::Magick
2
+
3
+ # Exception that is raised when a pattern is not configured properly.
4
+ class PatternException < Exception; end
5
+
6
+ module Plugins
7
+ # Draws a pattern and returns a B/W {Canvas} ready for masking.
8
+ #
9
+ # Chris Eppstein's original tweet:
10
+ # {http://twitter.com/chriseppstein/status/56095925843668992}
11
+ #
12
+ # @param [Sass::Script::Number] width The width of the pattern.
13
+ # @param [Sass::Script::Number] height The height of the pattern.
14
+ # @param [Sass::Script::List] values The pattern itself. This is a list
15
+ # of values (or a multi-line string) where `1`, `true`, `yes`, `X`, `*`
16
+ # and `+` mark where an opaque white pixel will be placed. Any other
17
+ # value is ignored and is transparent in the output. The size of the
18
+ # list must match the width/height.
19
+ # @return {Canvas} A B/W Canvas with the pattern applied. The resulting
20
+ # image can be applied as a mask.
21
+ # @example Diagonal stripes:
22
+ # magick-pattern(3, 3,
23
+ # x _ _
24
+ # _ x _
25
+ # _ _ x
26
+ # );
27
+ def magick_pattern(width, height, values)
28
+ Compass::Magick::Utils.assert_type 'width', width, Sass::Script::Number
29
+ Compass::Magick::Utils.assert_type 'height', height, Sass::Script::Number
30
+ Compass::Magick::Utils.assert_one_of 'magick-pattern(..)', values, Sass::Script::List, Sass::Script::String
31
+ if values.kind_of?(Sass::Script::String)
32
+ list = values.value.strip().split(/[\r\n]+/).map { |line| line.strip().split(/\s/) }.flatten
33
+ else
34
+ list = values.value
35
+ end
36
+ size = width.value * height.value
37
+ raise PatternException.new("magick-pattern(..) expects #{size} values, got #{list.size} instead: #{list.inspect}") unless size == list.size
38
+ canvas = Canvas.new(width, height)
39
+ opaque = ['1', 'true', 'yes', 'X', '*', '+']
40
+ for y in (0...height.value)
41
+ for x in (0...width.value)
42
+ pixel = list[x + y * height.value].to_s.upcase
43
+ canvas.set_pixel(x, y, ChunkyPNG::Color::WHITE) if opaque.include?(pixel)
44
+ end
45
+ end
46
+ canvas
47
+ end
48
+ end
49
+ end
File without changes
@@ -0,0 +1,19 @@
1
+ require 'helpers'
2
+
3
+ describe Compass::Magick::Canvas do
4
+ describe "#initialize" do
5
+ it "should assert arguments' type" do
6
+ lambda { Compass::Magick::Canvas.new(100, 100) }.should raise_error(Compass::Magick::TypeMismatch)
7
+ end
8
+ end
9
+
10
+ subject { Compass::Magick::Canvas.new(Sass::Script::Number.new(100), Sass::Script::Number.new(100)) }
11
+
12
+ it "should be transparent" do
13
+ subject.get_pixel(0, 0).should == ChunkyPNG::Color::TRANSPARENT
14
+ end
15
+
16
+ it "should encode the image in Base64" do
17
+ subject.to_data_uri.value.include?('data:image/png;base64,').should be_true
18
+ end
19
+ end
data/spec/helpers.rb ADDED
@@ -0,0 +1,5 @@
1
+ $: << File.join(File.dirname(__FILE__), '..', 'lib', 'magick')
2
+
3
+ require 'compass'
4
+ require 'chunky_png'
5
+ require 'magick'
@@ -0,0 +1,29 @@
1
+ require 'helpers'
2
+
3
+ describe Compass::Magick::Types::Gradients::Linear do
4
+ describe "#initialize" do
5
+ it "should assert arguments' type" do
6
+ lambda { Compass::Magick::Types::Gradients::Linear.new(45, 'string') }.should raise_error(Compass::Magick::TypeMismatch)
7
+ lambda { Compass::Magick::Types::Gradients::Linear.new(Sass::Script::Number.new(45), 'string') }.should raise_error(Compass::Magick::TypeMismatch)
8
+ lambda { Compass::Magick::Types::Gradients::Linear.new(Sass::Script::Number.new(45), ['string']) }.should raise_error(Compass::Magick::TypeMismatch)
9
+ end
10
+ end
11
+
12
+ subject { Compass::Magick::Types::Gradients::Linear.new(
13
+ Sass::Script::Number.new(45), [
14
+ Compass::Magick::Types::Gradients::ColorStop.new(Sass::Script::Number.new(0), Sass::Script::Color.new([255, 0, 0, 1])),
15
+ Compass::Magick::Types::Gradients::ColorStop.new(Sass::Script::Number.new(50), Sass::Script::Color.new([ 0, 255, 0, 0.5])),
16
+ Compass::Magick::Types::Gradients::ColorStop.new(Sass::Script::Number.new(100), Sass::Script::Color.new([ 0, 0, 255, 1]))
17
+ ]
18
+ ) }
19
+
20
+ it { should respond_to(:angle) }
21
+ it { should respond_to(:stops) }
22
+
23
+ it "should generate a linear-filled Canvas" do
24
+ canvas = subject.to_canvas(Sass::Script::Number.new(101), Sass::Script::Number.new(101))
25
+ canvas.get_pixel( 0, 0).should == ChunkyPNG::Color.rgba(255, 0, 0, 255)
26
+ canvas.get_pixel( 50, 50).should == ChunkyPNG::Color.rgba( 0, 255, 0, 127)
27
+ canvas.get_pixel(100, 100).should == ChunkyPNG::Color.rgba( 0, 0, 255, 255)
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ require 'helpers'
2
+
3
+ describe Compass::Magick::Types::Solid do
4
+ describe "#initialize" do
5
+ it "should assert arguments' type" do
6
+ lambda { Compass::Magick::Types::Solid.new('#ff0000') }.should raise_error(Compass::Magick::TypeMismatch)
7
+ end
8
+ end
9
+
10
+ subject { Compass::Magick::Types::Solid.new(Sass::Script::Color.new([255, 0, 0])) }
11
+
12
+ it { should respond_to(:color) }
13
+
14
+ it "should generate a solid Canvas" do
15
+ canvas = subject.to_canvas(Sass::Script::Number.new(100), Sass::Script::Number.new(100))
16
+ canvas.get_pixel( 0, 0).should == ChunkyPNG::Color.rgba(255, 0, 0, 255)
17
+ canvas.get_pixel(99, 99).should == ChunkyPNG::Color.rgba(255, 0, 0, 255)
18
+ end
19
+ end
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: compass-magick
3
+ version: !ruby/object:Gem::Version
4
+ hash: 31
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 2
10
+ version: 0.1.2
11
+ platform: ruby
12
+ authors:
13
+ - Stan Angeloff
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-04-16 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: compass
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ hash: 62196225
29
+ segments:
30
+ - 0
31
+ - 11
32
+ - beta
33
+ - 5
34
+ version: 0.11.beta.5
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: chunky_png
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ hash: 19
46
+ segments:
47
+ - 1
48
+ - 1
49
+ - 0
50
+ version: 1.1.0
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: rspec
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ hash: 15
62
+ segments:
63
+ - 2
64
+ - 0
65
+ - 0
66
+ version: 2.0.0
67
+ type: :development
68
+ version_requirements: *id003
69
+ description:
70
+ email:
71
+ - stanimir@angeloff.name
72
+ executables: []
73
+
74
+ extensions: []
75
+
76
+ extra_rdoc_files: []
77
+
78
+ files:
79
+ - README.md
80
+ - LICENSE.md
81
+ - lib/magick/canvas.rb
82
+ - lib/magick/command.rb
83
+ - lib/magick/effect.rb
84
+ - lib/magick/functions/canvas.rb
85
+ - lib/magick/functions/drawing.rb
86
+ - lib/magick/functions/operations/effects.rb
87
+ - lib/magick/functions/operations.rb
88
+ - lib/magick/functions/sprites.rb
89
+ - lib/magick/functions/types.rb
90
+ - lib/magick/functions.rb
91
+ - lib/magick/plugins.rb
92
+ - lib/magick/scriptable.rb
93
+ - lib/magick/shapes.rb
94
+ - lib/magick/types/gradients.rb
95
+ - lib/magick/types/solid.rb
96
+ - lib/magick/types.rb
97
+ - lib/magick/utils.rb
98
+ - lib/magick.rb
99
+ - lib/plugins/corners.rb
100
+ - lib/plugins/pattern.rb
101
+ - lib/stylesheets/_magick.sass
102
+ - spec/canvas_spec.rb
103
+ - spec/helpers.rb
104
+ - spec/types/gradients_spec.rb
105
+ - spec/types/solid_spec.rb
106
+ homepage: https://github.com/StanAngeloff/compass-magick
107
+ licenses: []
108
+
109
+ post_install_message:
110
+ rdoc_options: []
111
+
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ hash: 3
120
+ segments:
121
+ - 0
122
+ version: "0"
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ hash: 3
129
+ segments:
130
+ - 0
131
+ version: "0"
132
+ requirements: []
133
+
134
+ rubyforge_project:
135
+ rubygems_version: 1.7.2
136
+ signing_key:
137
+ specification_version: 3
138
+ summary: Dynamic image generation for Compass using ChunkyPNG.
139
+ test_files:
140
+ - spec/canvas_spec.rb
141
+ - spec/helpers.rb
142
+ - spec/types/gradients_spec.rb
143
+ - spec/types/solid_spec.rb
144
+ has_rdoc: true