compass-canvas 0.0.4 → 0.0.5

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.
data/README.md CHANGED
@@ -73,6 +73,12 @@ For a complete reference on Cairo methods, visit [Pycairo documentation][pycairo
73
73
  [cairo-tutorial]: http://zetcode.com/tutorials/cairographicstutorial/
74
74
  [pycairo]: http://cairographics.org/documentation/pycairo/3/reference/context.html#class-context
75
75
 
76
+ Similar Projects
77
+ ----------------
78
+
79
+ [compass-magick](https://github.com/StanAngeloff/compass-magick) is a pure Ruby dynamic image generation for Compass using ChunkyPNG/PhantomJS (no dependency on RMagick despite the name).
80
+ If you are looking for a project to generate image gradients or small & simple buttons, go check it out.
81
+
76
82
  ### Copyright
77
83
 
78
84
  > Copyright (c) 2011 Stan Angeloff. See [LICENSE.md](https://github.com/StanAngeloff/compass-canvas/blob/master/LICENSE.md) for details.
@@ -7,7 +7,7 @@ module Compass::Canvas
7
7
  # The project and Gem version. When building a Gem file for release, the
8
8
  # version is stripped to X.Y.Z. If you are using a Git cloned-repository,
9
9
  # the version will end in +.git+.
10
- VERSION = '0.0.4.git'
10
+ VERSION = '0.0.5.git'
11
11
 
12
12
  # The default backend for drawing.
13
13
  BACKEND = 'cairo'
@@ -20,6 +20,19 @@ module Compass::Canvas
20
20
  File.expand_path(File.join(File.dirname(__FILE__), '..', directory))
21
21
  end
22
22
 
23
+ # Helper function to normalize a CSS path to a filesystem path.
24
+ #
25
+ # @param [String] file A CSS file, usually with url(..) and optionally a cache buster.
26
+ # @return [String] The absolute filesystem path.
27
+ def self.absolute_path_to(file)
28
+ if file.include?('url(')
29
+ file = File.join(Compass.configuration.css_path, file.gsub(/^url\(['"]?|["']?\)$/, ''))
30
+ else
31
+ file = File.join(Compass.configuration.images_path, file)
32
+ end
33
+ file.split('?').shift()
34
+ end
35
+
23
36
  # Locations where plug-ins are installed. These paths are scanned for *.rb files
24
37
  # and loaded in order.
25
38
  PLUGINS_PATH = [
@@ -1,39 +1,40 @@
1
1
  module Compass::Canvas
2
2
  # This module contains all actions a backend must implement.
3
3
  module Actions
4
- ANTIALIAS = :antialias
5
- ARC = :arc
6
- ARC_REVERSE = :arc_reverse
7
- BRUSH = :brush
8
- CLIP = :clip
9
- CLOSE = :close
10
- CURVE = :curve
11
- DASH_PATTERN = :dash_pattern
12
- FILL = :fill
13
- FILL_RULE = :fill_rule
14
- GROUP = :group
15
- LINE = :line
16
- LINE_CAP = :line_cap
17
- LINE_JOIN = :line_join
18
- LINE_WIDTH = :line_width
19
- MASK = :mask
20
- MITER_LIMIT = :miter_limit
21
- MOVE = :move
22
- PAINT = :paint
23
- POP = :pop
24
- PUSH = :push
25
- RESET = :reset
26
- RESTORE = :restore
27
- RETRIEVE = :retrieve
28
- ROTATE = :rotate
29
- SAVE = :save
30
- SCALE = :scale
31
- SLOW_BLUR = :slow_blur
32
- STORE = :store
33
- STROKE = :stroke
34
- TOLERANCE = :tolerance
35
- TRANSFORM = :transform
36
- TRANSLATE = :translate
37
- UNCLIP = :unclip
4
+ ANTIALIAS = :antialias
5
+ ARC = :arc
6
+ ARC_REVERSE = :arc_reverse
7
+ BRUSH = :brush
8
+ CLIP = :clip
9
+ CLOSE = :close
10
+ CURVE = :curve
11
+ DASH_PATTERN = :dash_pattern
12
+ FILL = :fill
13
+ FILL_RULE = :fill_rule
14
+ GROUP = :group
15
+ LINE = :line
16
+ LINE_CAP = :line_cap
17
+ LINE_JOIN = :line_join
18
+ LINE_WIDTH = :line_width
19
+ MASK = :mask
20
+ MITER_LIMIT = :miter_limit
21
+ MOVE = :move
22
+ PAINT = :paint
23
+ POP = :pop
24
+ PUSH = :push
25
+ QUADRATIC_CURVE = :quadratic_curve
26
+ RESET = :reset
27
+ RESTORE = :restore
28
+ RETRIEVE = :retrieve
29
+ ROTATE = :rotate
30
+ SAVE = :save
31
+ SCALE = :scale
32
+ SLOW_BLUR = :slow_blur
33
+ STORE = :store
34
+ STROKE = :stroke
35
+ TOLERANCE = :tolerance
36
+ TRANSFORM = :transform
37
+ TRANSLATE = :translate
38
+ UNCLIP = :unclip
38
39
  end
39
40
  end
@@ -6,6 +6,7 @@ module Compass::Canvas::Backend
6
6
  #
7
7
  # Each implementation must respond to four methods:
8
8
  # - {Compass::Canvas::Backend::Base::load_dependencies} - initializes the backend by loading third-party dependencies
9
+ # - {Compass::Canvas::Backend::Base::read_canvas} - reads a canvas from a file
9
10
  # - {Compass::Canvas::Backend::Base::begin_canvas} - initialization code before the canvas is drawn
10
11
  # - {Compass::Canvas::Backend::Base::execute_one} - executes a single action on the canvas
11
12
  # - {Compass::Canvas::Backend::Base::to_blob} - clean up code, must return a
@@ -35,20 +36,15 @@ module Compass::Canvas::Backend
35
36
  load_dependencies
36
37
  if args[0].is_a?(String)
37
38
  file = args.shift
38
- unless args[1].is_a?(Fixnum)
39
- if file.include?('url(')
40
- file = File.join(Compass.configuration.css_path, file.gsub(/^url\(['"]?|["']?\)$/, '').split('?').shift())
41
- else
42
- file = File.join(Compass.configuration.images_path, file.split('?').shift())
43
- end
44
- end
39
+ file = Compass::Canvas.absolute_path_to(file) unless args[0].is_a?(Fixnum)
45
40
  @file = file
46
41
  end
47
42
  if args[0].is_a?(Fixnum)
48
43
  @width = args.shift
49
44
  @height = args.shift
50
45
  end
51
- @actions = args
46
+ @actions = args
47
+ @executed = false
52
48
  end
53
49
 
54
50
  # Abstract method.
@@ -60,6 +56,15 @@ module Compass::Canvas::Backend
60
56
  raise Compass::Canvas::Exception.new("(#{self.class}) Class must implement '#{this_method}'.")
61
57
  end
62
58
 
59
+ # Abstract method.
60
+ #
61
+ # Reads a canvas from a file
62
+ #
63
+ # @raise [Compass::Canvas::Exception] Backend implementation must override this method.
64
+ def read_canvas
65
+ raise Compass::Canvas::Exception.new("(#{self.class}) Class must implement '#{this_method}'.")
66
+ end
67
+
63
68
  # Abstract method.
64
69
  #
65
70
  # Initialization code before the canvas is drawn.
@@ -87,10 +92,32 @@ module Compass::Canvas::Backend
87
92
  raise Compass::Canvas::Exception.new("(#{self.class}) Class must implement '#{this_method}'.")
88
93
  end
89
94
 
95
+ # Reads a property of the backend.
96
+ #
97
+ # This can be used to provide custom information about a backend, such as
98
+ # width, height, the current point's position, etc.
99
+ #
100
+ # @param [String] name The property name.
101
+ # @return [Object] The property value, or nil if it doesn't exist.
102
+ def property(name)
103
+ case name
104
+ when :width; return @width
105
+ when :height; return @height
106
+ else return nil
107
+ end
108
+ end
109
+
90
110
  # Creates an empty canvas and executes all stored actions.
91
111
  def execute
92
- begin_canvas
93
- execute_actions
112
+ return self if @executed
113
+ if @width && @height
114
+ begin_canvas
115
+ execute_actions
116
+ else
117
+ read_canvas
118
+ end
119
+ @executed = true
120
+ self
94
121
  end
95
122
 
96
123
  # Returns the canvas as a Base64 encoded Data URI or as a file on disk
@@ -130,7 +157,6 @@ module Compass::Canvas::Backend
130
157
  end
131
158
  execute_one(action, *args)
132
159
  end
133
- self
134
160
  end
135
161
 
136
162
  private
@@ -25,6 +25,30 @@ module Compass::Canvas::Backend
25
25
  end
26
26
  end
27
27
 
28
+ # Reads a property of the Cairo backend.
29
+ #
30
+ # This can be used to obtain information about the width/height of the
31
+ # surface as well as the current point's X/Y coordinates.
32
+ #
33
+ # @param [String] name The property name.
34
+ # @return [Object] The property value, or nil if it doesn't exist.
35
+ def property(name)
36
+ execute
37
+ case name
38
+ when :width; return @surface.width
39
+ when :height; return @surface.height
40
+ when :x; return @context.current_point[0]
41
+ when :y; return @context.current_point[1]
42
+ else return nil
43
+ end
44
+ end
45
+
46
+ # Creates a new +ImageSurface+ from a file
47
+ def read_canvas
48
+ @surface = ::Cairo::ImageSurface.from_png(@file)
49
+ bind_context
50
+ end
51
+
28
52
  # Creates a new +ImageSurface+ and binds a new context to it.
29
53
  def begin_canvas
30
54
  if @width && @height
@@ -32,9 +56,7 @@ module Compass::Canvas::Backend
32
56
  else
33
57
  @surface = ::Cairo::ImageSurface.from_png(@file)
34
58
  end
35
- @context = ::Cairo::Context.new(@surface)
36
- @context.set_line_width(1)
37
- @sources = []
59
+ bind_context
38
60
  end
39
61
 
40
62
  # Executes a single action on the context bound to the surface.
@@ -46,6 +68,14 @@ module Compass::Canvas::Backend
46
68
  @context.line_to(*args)
47
69
  when Compass::Canvas::Actions::CURVE
48
70
  @context.curve_to(*args)
71
+ when Compass::Canvas::Actions::QUADRATIC_CURVE
72
+ x1, y1, x2, y2 = args
73
+ x, y = @context.current_point
74
+ @context.curve_to(
75
+ x + 2.0 / 3.0 * (x1 - x), y + 2.0 / 3.0 * (y1 - y),
76
+ x2 + 2.0 / 3.0 * (x1 - x2), y2 + 2.0 / 3.0 * (y1 - y2),
77
+ x2, y2
78
+ )
49
79
  when Compass::Canvas::Actions::ARC
50
80
  @context.arc(*args)
51
81
  when Compass::Canvas::Actions::ARC_REVERSE
@@ -117,8 +147,8 @@ module Compass::Canvas::Backend
117
147
  pattern.set_extend(constant('EXTEND', args))
118
148
  @context.mask(pattern)
119
149
  else
120
- x = args.shift if args.length
121
- y = args.shift if args.length
150
+ x = args.shift if args.length > 0
151
+ y = args.shift if args.length > 0
122
152
  @context.mask(surface, x || 0, y || 0)
123
153
  end
124
154
  elsif type == Compass::Canvas::Actions::RETRIEVE
@@ -142,7 +172,7 @@ module Compass::Canvas::Backend
142
172
  canvas = args.shift
143
173
  if canvas.is_a?(Compass::Canvas::Backend::Cairo)
144
174
  pattern = ::Cairo::SurfacePattern.new(canvas.execute.surface)
145
- pattern.set_extend(constant('EXTEND', args)) if args.length
175
+ pattern.set_extend(constant('EXTEND', args)) if args.length > 0
146
176
  @context.set_source(pattern)
147
177
  else
148
178
  raise Compass::Canvas::Exception.new("(#{self.class}.#{action}) Unsupported canvas, Cairo can only paint with Cairo: #{canvas.inspect}")
@@ -169,6 +199,12 @@ module Compass::Canvas::Backend
169
199
 
170
200
  private
171
201
 
202
+ def bind_context
203
+ @context = ::Cairo::Context.new(@surface)
204
+ @context.set_line_width(1)
205
+ @sources = []
206
+ end
207
+
172
208
  def constant(name, *args)
173
209
  ::Cairo::const_get("#{ name.upcase }_#{ args.join('_').gsub('-', '_').upcase }")
174
210
  end
@@ -16,6 +16,11 @@ module Compass::Canvas::Backend::Interface
16
16
  [x1.value, y1.value, x2.value, y2.value, x3.value, y3.value]
17
17
  end
18
18
 
19
+ # Unpacks arguments +X+[1..2] and +Y+[1..2] from Sass to Ruby objects.
20
+ def quadratic_curve(x1, y1, x2, y2)
21
+ [x1.value, y1.value, x2.value, y2.value]
22
+ end
23
+
19
24
  # Unpacks arguments +X+, +Y+, +radius+ and +angle+[1..2] from Sass to Ruby objects.
20
25
  def arc(x, y, radius, angle1, angle2)
21
26
  [x.value, y.value, radius.value, angle1.value * (Math::PI / 180.0), angle2.value * (Math::PI / 180.0)]
@@ -16,6 +16,34 @@ module Compass::Canvas
16
16
  end
17
17
  klass.new(*Compass::Canvas::Functions.unpack(args).flatten)
18
18
  end
19
+
20
+ # Gets the width of a {Compass::Canvas::Backend}.
21
+ #
22
+ # @return [Compass::Canvas::Backend] The width of the backend.
23
+ def width_of(canvas)
24
+ Sass::Script::Number.new(canvas.property(:width))
25
+ end
26
+
27
+ # Gets the height of a {Compass::Canvas::Backend}.
28
+ #
29
+ # @return [Compass::Canvas::Backend] The height of the backend.
30
+ def height_of(canvas)
31
+ Sass::Script::Number.new(canvas.property(:height))
32
+ end
33
+
34
+ # Gets the X position of the current path on a {Compass::Canvas::Backend}.
35
+ #
36
+ # @return [Compass::Canvas::Backend] The X position of the current backend path.
37
+ def path_x(canvas)
38
+ Sass::Script::Number.new(canvas.property(:x))
39
+ end
40
+
41
+ # Gets the Y position of the current path on a {Compass::Canvas::Backend}.
42
+ #
43
+ # @return [Compass::Canvas::Backend] The Y position of the current backend path.
44
+ def path_y(canvas)
45
+ Sass::Script::Number.new(canvas.property(:y))
46
+ end
19
47
  end
20
48
  end
21
49
  end
@@ -1,3 +1,27 @@
1
1
  @import 'canvas/context';
2
2
  @import 'canvas/path';
3
3
  @import 'canvas/pattern';
4
+
5
+ // @function width-of(canvas) {}
6
+ // @function height-of(canvas) {}
7
+ // @function path-x(canvas) {}
8
+ // @function path-y(canvas) {}
9
+
10
+ @function put-image($file, $x: 0, $y: 0) {
11
+ $canvas: canvas($file);
12
+ @if ($x == 'repeat') {
13
+ @return (
14
+ brush($canvas, $x)
15
+ paint
16
+ );
17
+ } @else {
18
+ @return (
19
+ save
20
+ translate($x, $y)
21
+ brush($canvas)
22
+ rectangle(0, 0, width-of($canvas), height-of($canvas))
23
+ fill
24
+ restore
25
+ );
26
+ }
27
+ }
@@ -1,2 +1,3 @@
1
+ @import 'canvas/path/curves';
1
2
  @import 'canvas/path/primitives';
2
3
  @import 'canvas/path/shapes';
@@ -0,0 +1,7 @@
1
+ @function bezier-curve-to($x1, $y1, $x2, $y2, $x3, $y3) {
2
+ @return curve-to($x1, $y1, $x2, $y2, $x3, $y3);
3
+ }
4
+
5
+ @function quadratic-curve-to($x1, $y1, $x2, $y2) {
6
+ @return canvas-path('quadratic_curve', $x1, $y1, $x2, $y2);
7
+ }
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: compass-canvas
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 4
10
- version: 0.0.4
9
+ - 5
10
+ version: 0.0.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Stan Angeloff
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-08-14 00:00:00 Z
18
+ date: 2011-08-29 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: compass
@@ -79,9 +79,10 @@ files:
79
79
  - stylesheets/canvas/_pattern.scss
80
80
  - stylesheets/canvas/_path.scss
81
81
  - stylesheets/canvas/_context.scss
82
+ - stylesheets/canvas/path/_curves.scss
82
83
  - stylesheets/canvas/path/_primitives.scss
83
84
  - stylesheets/canvas/path/_shapes.scss
84
- - plugins/drop-shadow.rb
85
+ - plugins/drop_shadow.rb
85
86
  homepage: http://StanAngeloff.github.com/compass-canvas/
86
87
  licenses: []
87
88