rmagick 2.15.3 → 2.15.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rmagick might be problematic. Click here for more details.

Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +14 -0
  3. data/.rubocop.yml +27 -3
  4. data/.travis.yml +9 -6
  5. data/CHANGELOG.md +4 -0
  6. data/CONTRIBUTING.md +10 -0
  7. data/README.textile +4 -0
  8. data/before_install_linux.sh +4 -4
  9. data/doc/ex/gravity.rb +2 -1
  10. data/ext/RMagick/extconf.rb +60 -17
  11. data/lib/rmagick/version.rb +1 -1
  12. data/lib/rvg/clippath.rb +37 -36
  13. data/lib/rvg/container.rb +106 -107
  14. data/lib/rvg/deep_equal.rb +46 -48
  15. data/lib/rvg/describable.rb +35 -36
  16. data/lib/rvg/embellishable.rb +384 -380
  17. data/lib/rvg/misc.rb +705 -690
  18. data/lib/rvg/paint.rb +39 -40
  19. data/lib/rvg/pathdata.rb +120 -121
  20. data/lib/rvg/rvg.rb +212 -209
  21. data/lib/rvg/stretchable.rb +159 -158
  22. data/lib/rvg/stylable.rb +99 -100
  23. data/lib/rvg/text.rb +0 -1
  24. data/lib/rvg/transformable.rb +110 -110
  25. data/lib/rvg/units.rb +58 -58
  26. data/rmagick.gemspec +1 -1
  27. data/spec/rmagick/image/blue_shift_spec.rb +16 -0
  28. data/spec/rmagick/image/composite_spec.rb +140 -0
  29. data/spec/rmagick/image/constitute_spec.rb +15 -0
  30. data/spec/rmagick/image/dispatch_spec.rb +18 -0
  31. data/spec/rmagick/image/from_blob_spec.rb +14 -0
  32. data/spec/rmagick/image/ping_spec.rb +14 -0
  33. data/spec/rmagick/image/properties_spec.rb +29 -0
  34. data/spec/spec_helper.rb +3 -0
  35. data/test/Image1.rb +524 -718
  36. data/test/Image2.rb +1262 -1262
  37. data/test/Image3.rb +973 -973
  38. data/test/ImageList2.rb +341 -341
  39. data/test/Image_attributes.rb +678 -678
  40. data/test/Info.rb +336 -336
  41. data/test/Magick.rb +245 -242
  42. data/test/Pixel.rb +105 -105
  43. data/test/Preview.rb +42 -42
  44. metadata +21 -6
@@ -2,163 +2,164 @@
2
2
  # $Id: stretchable.rb,v 1.7 2009/02/28 23:52:28 rmagick Exp $
3
3
  # Copyright (C) 2009 Timothy P. Hunter
4
4
  #++
5
-
6
5
  module Magick
7
- class RVG
8
- module PreserveAspectRatio
9
- #--
10
- # Included in Stretchable module and Image class
11
- #++
12
- # Specifies how the image within a viewport should be scaled.
13
- # [+align+] a combination of 'xMin', 'xMid', or 'xMax', followed by
14
- # 'YMin', 'YMid', or 'YMax'
15
- # [+meet_or_slice+] one of 'meet' or 'slice'
16
- def preserve_aspect_ratio(align, meet_or_slice='meet')
17
- @align = align.to_s
18
- if @align != 'none'
19
- m = /\A(xMin|xMid|xMax)(YMin|YMid|YMax)\z/.match(@align)
20
- fail(ArgumentError, "unknown alignment specifier: #{@align}") unless m
21
- end
22
-
23
- if meet_or_slice
24
- meet_or_slice = meet_or_slice.to_s.downcase
25
- if meet_or_slice == 'meet' || meet_or_slice == 'slice'
26
- @meet_or_slice = meet_or_slice
27
- else
28
- fail(ArgumentError, "specifier must be `meet' or `slice' (got #{meet_or_slice})")
29
- end
30
- end
31
- yield(self) if block_given?
32
- self
33
- end
34
- end # module PreserveAspectRatio
35
-
36
- # The methods in this module describe the user-coordinate space.
37
- # RVG and Pattern objects are stretchable.
38
- module Stretchable
39
- private
40
-
41
- # Scale to fit
42
- def set_viewbox_none(width, height)
43
- sx, sy = 1.0, 1.0
44
-
45
- if @vbx_width
46
- sx = width / @vbx_width
47
- end
48
- if @vbx_height
49
- sy = height / @vbx_height
50
- end
51
-
52
- [sx, sy]
53
- end
54
-
55
- # Use align attribute to compute x- and y-offset from viewport's upper-left corner.
56
- def align_to_viewport(width, height, sx, sy)
57
- tx = case @align
58
- when /\AxMin/
59
- 0
60
- when NilClass, /\AxMid/
61
- (width - @vbx_width*sx) / 2.0
62
- when /\AxMax/
63
- width - @vbx_width*sx
64
- end
65
-
66
- ty = case @align
67
- when /YMin\z/
68
- 0
69
- when NilClass, /YMid\z/
70
- (height - @vbx_height*sy) / 2.0
71
- when /YMax\z/
72
- height - @vbx_height*sy
73
- end
74
- [tx, ty]
75
- end
76
-
77
- # Scale to smaller viewbox dimension
78
- def set_viewbox_meet(width, height)
79
- sx = sy = [width / @vbx_width, height / @vbx_height].min
80
- [sx, sy]
81
- end
82
-
83
- # Scale to larger viewbox dimension
84
- def set_viewbox_slice(width, height)
85
- sx = sy = [width / @vbx_width, height / @vbx_height].max
86
- [sx, sy]
87
- end
88
-
89
- # Establish the viewbox as necessary
90
- def add_viewbox_primitives(width, height, gc)
91
- @vbx_width ||= width
92
- @vbx_height ||= height
93
- @vbx_x ||= 0.0
94
- @vbx_y ||= 0.0
95
-
96
- if @align == 'none'
97
- sx, sy = set_viewbox_none(width, height)
98
- tx, ty = 0, 0
99
- elsif @meet_or_slice == 'meet'
100
- sx, sy = set_viewbox_meet(width, height)
101
- tx, ty = align_to_viewport(width, height, sx, sy)
102
- else
103
- sx, sy = set_viewbox_slice(width, height)
104
- tx, ty = align_to_viewport(width, height, sx, sy)
105
- end
106
-
107
- # Establish clipping path around the current viewport
108
- name = __id__.to_s
109
- gc.define_clip_path(name) do
110
- gc.path("M0,0 l#{width},0 l0,#{height} l-#{width},0 l0,-#{height}z")
111
- end
112
-
113
- gc.clip_path(name)
114
- # Add a non-scaled translation if meet or slice
115
- gc.translate(tx, ty) if tx.abs > 1.0e-10 || ty.abs > 1.0e-10
116
- # Scale viewbox as necessary
117
- gc.scale(sx, sy) if sx != 1.0 || sy != 1.0
118
- # Add a scaled translation if non-0 origin
119
- gc.translate(-@vbx_x, -@vbx_y) if @vbx_x.abs != 0.0 || @vbx_y.abs != 0
120
- end
121
-
122
- def initialize(*args, &block)
123
- super()
124
- @vbx_x, @vbx_y, @vbx_width, @vbx_height = nil
125
- @meet_or_slice = 'meet'
126
- @align = nil
127
- end
128
-
129
- public
130
-
131
- include PreserveAspectRatio
132
-
133
- # Describe a user coordinate system to be imposed on the viewbox.
134
- # The arguments must be numbers and the +width+ and +height+
135
- # arguments must be positive.
136
- def viewbox(x, y, width, height)
137
- begin
138
- @vbx_x = Float(x)
139
- @vbx_y = Float(y)
140
- @vbx_width = Float(width)
141
- @vbx_height = Float(height)
142
- rescue ArgumentError
143
- raise ArgumentError, "arguments must be convertable to float (got #{x.class}, #{y.class}, #{width.class}, #{height.class})"
144
- end
145
- fail(ArgumentError, "viewbox width must be > 0 (#{width} given)") unless width >= 0
146
- fail(ArgumentError, "viewbox height must be > 0 (#{height} given)") unless height >= 0
147
-
148
- # return the user-coordinate space attributes if defined
149
- class << self
150
- unless defined? @redefined
151
- @redefined = true
152
- define_method(:x) { @vbx_x }
153
- define_method(:y) { @vbx_y }
154
- define_method(:width) { @vbx_width}
155
- define_method(:height) { @vbx_height }
156
- end
157
- end
158
-
159
- yield(self) if block_given?
160
- self
161
- end
162
- end # module Stretchable
163
- end # class RVG
6
+ class RVG
7
+ module PreserveAspectRatio
8
+ #--
9
+ # Included in Stretchable module and Image class
10
+ #++
11
+ # Specifies how the image within a viewport should be scaled.
12
+ # [+align+] a combination of 'xMin', 'xMid', or 'xMax', followed by
13
+ # 'YMin', 'YMid', or 'YMax'
14
+ # [+meet_or_slice+] one of 'meet' or 'slice'
15
+ def preserve_aspect_ratio(align, meet_or_slice='meet')
16
+ @align = align.to_s
17
+ if @align != 'none'
18
+ m = /\A(xMin|xMid|xMax)(YMin|YMid|YMax)\z/.match(@align)
19
+ fail(ArgumentError, "unknown alignment specifier: #{@align}") unless m
20
+ end
21
+
22
+ if meet_or_slice
23
+ meet_or_slice = meet_or_slice.to_s.downcase
24
+ if meet_or_slice == 'meet' || meet_or_slice == 'slice'
25
+ @meet_or_slice = meet_or_slice
26
+ else
27
+ fail(ArgumentError, "specifier must be `meet' or `slice' (got #{meet_or_slice})")
28
+ end
29
+ end
30
+ yield(self) if block_given?
31
+ self
32
+ end
33
+ end # module PreserveAspectRatio
34
+
35
+ # The methods in this module describe the user-coordinate space.
36
+ # RVG and Pattern objects are stretchable.
37
+ module Stretchable
38
+ private
39
+
40
+ # Scale to fit
41
+ def set_viewbox_none(width, height)
42
+ sx = 1.0
43
+ sy = 1.0
44
+
45
+ if @vbx_width
46
+ sx = width / @vbx_width
47
+ end
48
+ if @vbx_height
49
+ sy = height / @vbx_height
50
+ end
51
+
52
+ [sx, sy]
53
+ end
54
+
55
+ # Use align attribute to compute x- and y-offset from viewport's upper-left corner.
56
+ def align_to_viewport(width, height, sx, sy)
57
+ tx = case @align
58
+ when /\AxMin/
59
+ 0
60
+ when NilClass, /\AxMid/
61
+ (width - @vbx_width*sx) / 2.0
62
+ when /\AxMax/
63
+ width - @vbx_width*sx
64
+ end
65
+
66
+ ty = case @align
67
+ when /YMin\z/
68
+ 0
69
+ when NilClass, /YMid\z/
70
+ (height - @vbx_height*sy) / 2.0
71
+ when /YMax\z/
72
+ height - @vbx_height*sy
73
+ end
74
+ [tx, ty]
75
+ end
76
+
77
+ # Scale to smaller viewbox dimension
78
+ def set_viewbox_meet(width, height)
79
+ sx = sy = [width / @vbx_width, height / @vbx_height].min
80
+ [sx, sy]
81
+ end
82
+
83
+ # Scale to larger viewbox dimension
84
+ def set_viewbox_slice(width, height)
85
+ sx = sy = [width / @vbx_width, height / @vbx_height].max
86
+ [sx, sy]
87
+ end
88
+
89
+ # Establish the viewbox as necessary
90
+ def add_viewbox_primitives(width, height, gc)
91
+ @vbx_width ||= width
92
+ @vbx_height ||= height
93
+ @vbx_x ||= 0.0
94
+ @vbx_y ||= 0.0
95
+
96
+ if @align == 'none'
97
+ sx, sy = set_viewbox_none(width, height)
98
+ tx = 0
99
+ ty = 0
100
+ elsif @meet_or_slice == 'meet'
101
+ sx, sy = set_viewbox_meet(width, height)
102
+ tx, ty = align_to_viewport(width, height, sx, sy)
103
+ else
104
+ sx, sy = set_viewbox_slice(width, height)
105
+ tx, ty = align_to_viewport(width, height, sx, sy)
106
+ end
107
+
108
+ # Establish clipping path around the current viewport
109
+ name = __id__.to_s
110
+ gc.define_clip_path(name) do
111
+ gc.path("M0,0 l#{width},0 l0,#{height} l-#{width},0 l0,-#{height}z")
112
+ end
113
+
114
+ gc.clip_path(name)
115
+ # Add a non-scaled translation if meet or slice
116
+ gc.translate(tx, ty) if tx.abs > 1.0e-10 || ty.abs > 1.0e-10
117
+ # Scale viewbox as necessary
118
+ gc.scale(sx, sy) if sx != 1.0 || sy != 1.0
119
+ # Add a scaled translation if non-0 origin
120
+ gc.translate(-@vbx_x, -@vbx_y) if @vbx_x.abs != 0.0 || @vbx_y.abs != 0
121
+ end
122
+
123
+ def initialize(*args, &block)
124
+ super()
125
+ @vbx_x, @vbx_y, @vbx_width, @vbx_height = nil
126
+ @meet_or_slice = 'meet'
127
+ @align = nil
128
+ end
129
+
130
+ public
131
+
132
+ include PreserveAspectRatio
133
+
134
+ # Describe a user coordinate system to be imposed on the viewbox.
135
+ # The arguments must be numbers and the +width+ and +height+
136
+ # arguments must be positive.
137
+ def viewbox(x, y, width, height)
138
+ begin
139
+ @vbx_x = Float(x)
140
+ @vbx_y = Float(y)
141
+ @vbx_width = Float(width)
142
+ @vbx_height = Float(height)
143
+ rescue ArgumentError
144
+ raise ArgumentError, "arguments must be convertable to float (got #{x.class}, #{y.class}, #{width.class}, #{height.class})"
145
+ end
146
+ fail(ArgumentError, "viewbox width must be > 0 (#{width} given)") unless width >= 0
147
+ fail(ArgumentError, "viewbox height must be > 0 (#{height} given)") unless height >= 0
148
+
149
+ # return the user-coordinate space attributes if defined
150
+ class << self
151
+ unless defined? @redefined
152
+ @redefined = true
153
+ define_method(:x) { @vbx_x }
154
+ define_method(:y) { @vbx_y }
155
+ define_method(:width) { @vbx_width}
156
+ define_method(:height) { @vbx_height }
157
+ end
158
+ end
159
+
160
+ yield(self) if block_given?
161
+ self
162
+ end
163
+ end # module Stretchable
164
+ end # class RVG
164
165
  end # module Magick
@@ -2,116 +2,115 @@
2
2
  # $Id: stylable.rb,v 1.7 2009/02/28 23:52:28 rmagick Exp $
3
3
  # Copyright (C) 2009 Timothy P. Hunter
4
4
  #++
5
-
6
5
  module Magick
7
- class RVG
8
- #:stopdoc:
9
- STYLES = [:clip_path, :clip_rule, :fill, :fill_opacity, :fill_rule, :font,
10
- :font_family, :font_size, :font_stretch, :font_style, :font_weight,
11
- :opacity, :stroke, :stroke_dasharray, :stroke_dashoffset, :stroke_linecap,
12
- :stroke_linejoin, :stroke_miterlimit, :stroke_opacity, :stroke_width,
13
- :text_anchor, :text_decoration,
14
- :glyph_orientation_vertical, :glyph_orientation_horizontal,
15
- :letter_spacing, :word_spacing, :baseline_shift, :writing_mode]
6
+ class RVG
7
+ #:stopdoc:
8
+ STYLES = [:clip_path, :clip_rule, :fill, :fill_opacity, :fill_rule, :font,
9
+ :font_family, :font_size, :font_stretch, :font_style, :font_weight,
10
+ :opacity, :stroke, :stroke_dasharray, :stroke_dashoffset, :stroke_linecap,
11
+ :stroke_linejoin, :stroke_miterlimit, :stroke_opacity, :stroke_width,
12
+ :text_anchor, :text_decoration,
13
+ :glyph_orientation_vertical, :glyph_orientation_horizontal,
14
+ :letter_spacing, :word_spacing, :baseline_shift, :writing_mode]
16
15
 
17
- Styles = Struct.new(*STYLES)
16
+ Styles = Struct.new(*STYLES)
18
17
 
19
- # Styles is a Struct class with a couple of extra methods
20
- class Styles
21
- def set(styles)
22
- begin
23
- styles.each_pair do |style, value|
24
- begin
25
- self[style] = value
26
- rescue NoMethodError
27
- raise ArgumentError, "unknown style `#{style}'"
28
- end
29
- end
30
- rescue NoMethodError
31
- raise ArgumentError, "style arguments must be in the form `style => value'"
32
- end
33
- self
18
+ # Styles is a Struct class with a couple of extra methods
19
+ class Styles
20
+ def set(styles)
21
+ begin
22
+ styles.each_pair do |style, value|
23
+ begin
24
+ self[style] = value
25
+ rescue NoMethodError
26
+ raise ArgumentError, "unknown style `#{style}'"
34
27
  end
28
+ end
29
+ rescue NoMethodError
30
+ raise ArgumentError, "style arguments must be in the form `style => value'"
31
+ end
32
+ self
33
+ end
35
34
 
36
- # Iterate over the style names. Yield for each style that has a value.
37
- def each_value
38
- each_pair do |style, value|
39
- yield(style, value) if value
40
- end
41
- end
35
+ # Iterate over the style names. Yield for each style that has a value.
36
+ def each_value
37
+ each_pair do |style, value|
38
+ yield(style, value) if value
39
+ end
40
+ end
42
41
 
43
- # The "usual" deep_copy method doesn't copy a Struct correctly.
44
- def deep_copy(h=nil)
45
- copy = Styles.new
46
- each_pair { |style, value| copy[style] = value }
47
- copy
48
- end
49
- end # class Styles
42
+ # The "usual" deep_copy method doesn't copy a Struct correctly.
43
+ def deep_copy(h=nil)
44
+ copy = Styles.new
45
+ each_pair { |style, value| copy[style] = value }
46
+ copy
47
+ end
48
+ end # class Styles
50
49
 
51
- #:startdoc:
50
+ #:startdoc:
52
51
 
53
- # This module is mixed into classes that can have styles.
54
- module Stylable
55
- private
52
+ # This module is mixed into classes that can have styles.
53
+ module Stylable
54
+ private
56
55
 
57
- # For each style that has a value, add a style primitive to the gc.
58
- # Use splat to splat out Array arguments such as stroke_dasharray.
59
- def add_style_primitives(gc)
60
- @styles.each_value do |style, value|
61
- if value.respond_to? :add_primitives
62
- value.add_primitives(gc, style)
63
- else
64
- gc.__send__(style, *value)
65
- end
66
- end
67
- end
56
+ # For each style that has a value, add a style primitive to the gc.
57
+ # Use splat to splat out Array arguments such as stroke_dasharray.
58
+ def add_style_primitives(gc)
59
+ @styles.each_value do |style, value|
60
+ if value.respond_to? :add_primitives
61
+ value.add_primitives(gc, style)
62
+ else
63
+ gc.__send__(style, *value)
64
+ end
65
+ end
66
+ end
68
67
 
69
- def initialize
70
- super
71
- @styles = Styles.new
72
- end
68
+ def initialize
69
+ super
70
+ @styles = Styles.new
71
+ end
73
72
 
74
- public
73
+ public
75
74
 
76
- # This method can be used with any RVG, Group, Use, Text, or
77
- # shape object. The argument is a hash. The style names are
78
- # the hash keys. The style names and values are:
79
- # [:baseline_shift] modify the text baseline
80
- # [:clip_path] clipping path defined by clip_path
81
- # [:clip_rule] 'evenodd' or 'nozero'
82
- # [:fill] color name
83
- # [:fill_opacity] the fill opacity, 0.0<=N<=1.0
84
- # [:fill_rule] 'evenodd' or 'nozero'
85
- # [:font] font name or font file name
86
- # [:font_family] font family name, ex. 'serif'
87
- # [:font_size] font size in points
88
- # [:font_stretch] 'normal','ultra_condensed','extra_condensed',
89
- # 'condensed','semi_condensed','semi_expanded',
90
- # 'expanded','extra_expanded','ultra_expanded'
91
- # [:font_style] 'normal','italic','oblique'
92
- # [:font_weight] 'normal','bold','bolder','lighter', or
93
- # a multiple of 100 between 100 and 900.
94
- # [:glyph_orientation_horizontal] 0, 90, 180, 270
95
- # [:glyph_orientation_vertical] 0, 90, 180, 270
96
- # [:letter_spacing] modify the spacing between letters
97
- # [:opacity] both fill and stroke opacity, 0.0<=N<=1.0
98
- # [:stroke] color name
99
- # [:stroke_dasharray] dash pattern (Array)
100
- # [:stroke_dashoffset] initial distance into dash pattern
101
- # [:stroke_linecap] 'butt', 'round', 'square'
102
- # [:stroke_linejoin] 'miter', 'round', 'bevel'
103
- # [:stroke_miterlimit] miter length constraint
104
- # [:stroke_opacity] the stroke opacity, 0.0<=N<=1.0
105
- # [:stroke_width] stroke width
106
- # [:text_anchor] 'start','middle','end'
107
- # [:text_decoration] 'none','underline','overline','line_through'
108
- # [:word_spacing] modify the spacing between words
109
- # [:writing_mode] 'lr-tb', 'lr', 'rt-tb', 'rl', 'tb-rl', 'tb'
110
- def styles(styles)
111
- @styles.set(styles)
112
- yield(self) if block_given?
113
- self
114
- end
115
- end # module Stylable
116
- end # class RVG
75
+ # This method can be used with any RVG, Group, Use, Text, or
76
+ # shape object. The argument is a hash. The style names are
77
+ # the hash keys. The style names and values are:
78
+ # [:baseline_shift] modify the text baseline
79
+ # [:clip_path] clipping path defined by clip_path
80
+ # [:clip_rule] 'evenodd' or 'nozero'
81
+ # [:fill] color name
82
+ # [:fill_opacity] the fill opacity, 0.0<=N<=1.0
83
+ # [:fill_rule] 'evenodd' or 'nozero'
84
+ # [:font] font name or font file name
85
+ # [:font_family] font family name, ex. 'serif'
86
+ # [:font_size] font size in points
87
+ # [:font_stretch] 'normal','ultra_condensed','extra_condensed',
88
+ # 'condensed','semi_condensed','semi_expanded',
89
+ # 'expanded','extra_expanded','ultra_expanded'
90
+ # [:font_style] 'normal','italic','oblique'
91
+ # [:font_weight] 'normal','bold','bolder','lighter', or
92
+ # a multiple of 100 between 100 and 900.
93
+ # [:glyph_orientation_horizontal] 0, 90, 180, 270
94
+ # [:glyph_orientation_vertical] 0, 90, 180, 270
95
+ # [:letter_spacing] modify the spacing between letters
96
+ # [:opacity] both fill and stroke opacity, 0.0<=N<=1.0
97
+ # [:stroke] color name
98
+ # [:stroke_dasharray] dash pattern (Array)
99
+ # [:stroke_dashoffset] initial distance into dash pattern
100
+ # [:stroke_linecap] 'butt', 'round', 'square'
101
+ # [:stroke_linejoin] 'miter', 'round', 'bevel'
102
+ # [:stroke_miterlimit] miter length constraint
103
+ # [:stroke_opacity] the stroke opacity, 0.0<=N<=1.0
104
+ # [:stroke_width] stroke width
105
+ # [:text_anchor] 'start','middle','end'
106
+ # [:text_decoration] 'none','underline','overline','line_through'
107
+ # [:word_spacing] modify the spacing between words
108
+ # [:writing_mode] 'lr-tb', 'lr', 'rt-tb', 'rl', 'tb-rl', 'tb'
109
+ def styles(styles)
110
+ @styles.set(styles)
111
+ yield(self) if block_given?
112
+ self
113
+ end
114
+ end # module Stylable
115
+ end # class RVG
117
116
  end # module Magick