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.
- checksums.yaml +4 -4
- data/.editorconfig +14 -0
- data/.rubocop.yml +27 -3
- data/.travis.yml +9 -6
- data/CHANGELOG.md +4 -0
- data/CONTRIBUTING.md +10 -0
- data/README.textile +4 -0
- data/before_install_linux.sh +4 -4
- data/doc/ex/gravity.rb +2 -1
- data/ext/RMagick/extconf.rb +60 -17
- data/lib/rmagick/version.rb +1 -1
- data/lib/rvg/clippath.rb +37 -36
- data/lib/rvg/container.rb +106 -107
- data/lib/rvg/deep_equal.rb +46 -48
- data/lib/rvg/describable.rb +35 -36
- data/lib/rvg/embellishable.rb +384 -380
- data/lib/rvg/misc.rb +705 -690
- data/lib/rvg/paint.rb +39 -40
- data/lib/rvg/pathdata.rb +120 -121
- data/lib/rvg/rvg.rb +212 -209
- data/lib/rvg/stretchable.rb +159 -158
- data/lib/rvg/stylable.rb +99 -100
- data/lib/rvg/text.rb +0 -1
- data/lib/rvg/transformable.rb +110 -110
- data/lib/rvg/units.rb +58 -58
- data/rmagick.gemspec +1 -1
- data/spec/rmagick/image/blue_shift_spec.rb +16 -0
- data/spec/rmagick/image/composite_spec.rb +140 -0
- data/spec/rmagick/image/constitute_spec.rb +15 -0
- data/spec/rmagick/image/dispatch_spec.rb +18 -0
- data/spec/rmagick/image/from_blob_spec.rb +14 -0
- data/spec/rmagick/image/ping_spec.rb +14 -0
- data/spec/rmagick/image/properties_spec.rb +29 -0
- data/spec/spec_helper.rb +3 -0
- data/test/Image1.rb +524 -718
- data/test/Image2.rb +1262 -1262
- data/test/Image3.rb +973 -973
- data/test/ImageList2.rb +341 -341
- data/test/Image_attributes.rb +678 -678
- data/test/Info.rb +336 -336
- data/test/Magick.rb +245 -242
- data/test/Pixel.rb +105 -105
- data/test/Preview.rb +42 -42
- metadata +21 -6
data/lib/rvg/text.rb
CHANGED
data/lib/rvg/transformable.rb
CHANGED
@@ -2,125 +2,125 @@
|
|
2
2
|
# $Id: transformable.rb,v 1.5 2009/02/28 23:52:28 rmagick Exp $
|
3
3
|
# Copyright (C) 2009 Timothy P. Hunter
|
4
4
|
#++
|
5
|
-
|
6
5
|
module Magick
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
6
|
+
class RVG
|
7
|
+
# Transforms is an Array with a deep_copy method.
|
8
|
+
# During unit-testing it also has a deep_equal method.
|
9
|
+
class Transforms < Array #:nodoc:
|
10
|
+
def deep_copy(h = nil)
|
11
|
+
copy = self.class.new
|
12
|
+
each { |transform| copy << [transform[0], transform[1].dup] }
|
13
|
+
copy
|
14
|
+
end
|
15
|
+
end # class Transform
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
17
|
+
# Transformations are operations on the coordinate system.
|
18
|
+
# All the transformations defined within a container (an RVG object
|
19
|
+
# or a group) are applied before drawing any shapes or text.
|
20
|
+
# All transformations are applied in the order they were
|
21
|
+
# defined. <em>Note:</em> This means that
|
22
|
+
# g.translate(10,20).scale(2)
|
23
|
+
# is not the same as
|
24
|
+
# g.scale(2).translate(10,20)
|
25
|
+
module Transformable
|
26
|
+
private
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
# Apply transforms in the same order they were specified!
|
29
|
+
def add_transform_primitives(gc)
|
30
|
+
@transforms.each { |transform| gc.__send__(transform[0], *transform[1]) }
|
31
|
+
end
|
33
32
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
def initialize(*args, &block)
|
34
|
+
super()
|
35
|
+
@transforms = Transforms.new
|
36
|
+
end
|
38
37
|
|
39
|
-
|
38
|
+
public
|
40
39
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
40
|
+
# Applies the transformation matrix [sx, rx, ry, sy, tx, ty]
|
41
|
+
def matrix(sx, rx, ry, sy, tx, ty)
|
42
|
+
begin
|
43
|
+
@transforms << [:affine, [Float(sx), Float(rx), Float(ry), Float(sy), Float(tx), Float(ty)]]
|
44
|
+
rescue ArgumentError
|
45
|
+
raise ArgumentError, "arguments must be convertable to float (got #{sx.class}, #{rx.class}, #{ry.class}, #{sy.class}, #{sx.class}, #{sx.class}, #{tx.class}, #{ty.class})"
|
46
|
+
end
|
47
|
+
yield(self) if block_given?
|
48
|
+
self
|
49
|
+
end
|
51
50
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
51
|
+
# Add <tt>tx</tt> to all x-coordinates and <tt>ty</tt>
|
52
|
+
# to all y-coordinates. If <tt>ty</tt> is omitted it defaults
|
53
|
+
# to <tt>tx</tt>.
|
54
|
+
def translate(tx, ty = nil)
|
55
|
+
ty ||= tx
|
56
|
+
begin
|
57
|
+
@transforms << [:translate, [Float(tx), Float(ty)]]
|
58
|
+
rescue ArgumentError
|
59
|
+
raise ArgumentError, "arguments must be convertable to float (got #{tx.class}, #{ty.class})"
|
60
|
+
end
|
61
|
+
yield(self) if block_given?
|
62
|
+
self
|
63
|
+
end
|
65
64
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
65
|
+
# Multiply the x-coordinates by <tt>sx</tt> and the y-coordinates
|
66
|
+
# by <tt>sy</tt>. If <tt>sy</tt> is omitted it defaults to <tt>sx</tt>.
|
67
|
+
def scale(sx, sy = nil)
|
68
|
+
sy ||= sx
|
69
|
+
begin
|
70
|
+
@transforms << [:scale, [Float(sx), Float(sy)]]
|
71
|
+
rescue ArgumentError
|
72
|
+
raise ArgumentError, "arguments must be convertable to float (got #{sx.class}, #{sy.class})"
|
73
|
+
end
|
74
|
+
yield(self) if block_given?
|
75
|
+
self
|
76
|
+
end
|
78
77
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
78
|
+
# This method can take either of two argument lists:
|
79
|
+
# [rotate(angle)] rotate by <tt>angle</tt> degrees
|
80
|
+
# [rotate(angle, cx, cy)] rotate by <tt>angle</tt> degrees about
|
81
|
+
# the point [<tt>cx</tt>, <tt>cy</tt>].
|
82
|
+
def rotate(angle, *args)
|
83
|
+
begin
|
84
|
+
case args.length
|
85
|
+
when 0
|
86
|
+
@transforms << [:rotate, [Float(angle)]]
|
87
|
+
when 2
|
88
|
+
cx = Float(args[0])
|
89
|
+
cy = Float(args[1])
|
90
|
+
@transforms << [:translate, [cx, cy]]
|
91
|
+
@transforms << [:rotate, [angle]]
|
92
|
+
@transforms << [:translate, [-cx, -cy]]
|
93
|
+
else
|
94
|
+
fail ArgumentError, "wrong number of arguments (#{args.length} for 1 or 3)"
|
95
|
+
end
|
96
|
+
rescue ArgumentError
|
97
|
+
raise ArgumentError, "arguments must be convertable to float (got #{[angle, *args].collect {|a| a.class}.join(', ')})"
|
98
|
+
end
|
99
|
+
yield(self) if block_given?
|
100
|
+
self
|
101
|
+
end
|
102
102
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
103
|
+
# Skew the X-axis by <tt>angle</tt> degrees.
|
104
|
+
def skewX(angle)
|
105
|
+
begin
|
106
|
+
@transforms << [:skewx, [Float(angle)]]
|
107
|
+
rescue ArgumentError
|
108
|
+
raise ArgumentError, "argument must be convertable to float (got #{angle.class})"
|
109
|
+
end
|
110
|
+
yield(self) if block_given?
|
111
|
+
self
|
112
|
+
end
|
113
113
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
114
|
+
# Skew the Y-axis by <tt>angle</tt> degrees.
|
115
|
+
def skewY(angle)
|
116
|
+
begin
|
117
|
+
@transforms << [:skewy, [Float(angle)]]
|
118
|
+
rescue ArgumentError
|
119
|
+
raise ArgumentError, "argument must be convertable to float (got #{angle.class})"
|
120
|
+
end
|
121
|
+
yield(self) if block_given?
|
122
|
+
self
|
123
|
+
end
|
124
|
+
end # module Transformable
|
125
|
+
end # class RVG
|
126
126
|
end # module Magick
|
data/lib/rvg/units.rb
CHANGED
@@ -1,63 +1,63 @@
|
|
1
1
|
# $Id: units.rb,v 1.5 2009/02/28 23:52:28 rmagick Exp $
|
2
2
|
# Copyright (C) 2009 Timothy P. Hunter
|
3
3
|
module Magick
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
4
|
+
class RVG
|
5
|
+
# Define RVG.dpi and RVG.dpi=. Add conversions to Fixnum and Float classes
|
6
|
+
class << self
|
7
|
+
attr_reader :dpi
|
8
|
+
def dpi=(n)
|
9
|
+
unless defined?(@dpi)
|
10
|
+
[Float, Fixnum].each do |c|
|
11
|
+
c.class_eval <<-END_DEFS
|
12
|
+
# the default measurement - 1px is 1 pixel
|
13
|
+
def px
|
14
|
+
self
|
15
|
+
end
|
16
|
+
# inches
|
17
|
+
def in
|
18
|
+
self * ::Magick::RVG.dpi
|
19
|
+
end
|
20
|
+
# millimeters
|
21
|
+
def mm
|
22
|
+
self * ::Magick::RVG.dpi / 25.4
|
23
|
+
end
|
24
|
+
# centimeters
|
25
|
+
def cm
|
26
|
+
self * ::Magick::RVG.dpi / 2.54
|
27
|
+
end
|
28
|
+
# points
|
29
|
+
def pt
|
30
|
+
self * ::Magick::RVG.dpi / 72.0
|
31
|
+
end
|
32
|
+
# picas
|
33
|
+
def pc
|
34
|
+
self * ::Magick::RVG.dpi / 6.0
|
35
|
+
end
|
36
|
+
# percentage of the argument
|
37
|
+
def pct(of)
|
38
|
+
self * Float(of) / 100.0
|
39
|
+
end
|
40
|
+
# the default is deg
|
41
|
+
def deg
|
42
|
+
self
|
43
|
+
end
|
44
|
+
# radians -> degrees
|
45
|
+
def rad
|
46
|
+
self * 180.0 / Math::PI
|
47
|
+
end
|
48
|
+
# grads -> degrees
|
49
|
+
def grad
|
50
|
+
self * 9.0 / 10.0
|
51
|
+
end
|
52
|
+
END_DEFS
|
53
|
+
end
|
54
|
+
end
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
56
|
+
@dpi = Float(n)
|
57
|
+
return @dpi
|
58
|
+
rescue ArgumentError
|
59
|
+
raise TypeError, "Can't convert `#{n}' to Float"
|
60
|
+
end
|
61
|
+
end # class << self
|
62
|
+
end # class RVG
|
63
63
|
end # module Magick
|
data/rmagick.gemspec
CHANGED
@@ -33,7 +33,7 @@ Gem::Specification.new do |s|
|
|
33
33
|
s.add_development_dependency 'rspec', '~> 3.2.0'
|
34
34
|
|
35
35
|
if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('1.9.2')
|
36
|
-
s.add_development_dependency 'rubocop'
|
36
|
+
s.add_development_dependency 'rubocop', '~> 0.33.0'
|
37
37
|
end
|
38
38
|
|
39
39
|
if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.2.0')
|
@@ -0,0 +1,16 @@
|
|
1
|
+
RSpec.describe Magick::Image, '#blue_shift' do
|
2
|
+
|
3
|
+
let(:img) { Magick::Image.read(IMAGES_DIR+'/Button_0.gif').first }
|
4
|
+
|
5
|
+
it 'returns a new Image' do
|
6
|
+
res = img.blue_shift
|
7
|
+
expect(res).to be_instance_of(Magick::Image)
|
8
|
+
expect(res).not_to eq img
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'accepts one argument' do
|
12
|
+
expect { img.blue_shift(2) }.not_to raise_error
|
13
|
+
expect { img.blue_shift(2, 3) }.to raise_error(ArgumentError)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
RSpec.describe Magick::Image, '#composite' do
|
2
|
+
|
3
|
+
let(:img1) { Magick::Image.read(IMAGES_DIR+'/Button_0.gif').first }
|
4
|
+
let(:img2) { Magick::Image.read(IMAGES_DIR+'/Button_1.gif').first }
|
5
|
+
let(:composite_ops) do
|
6
|
+
[
|
7
|
+
Magick::UndefinedCompositeOp,
|
8
|
+
Magick::NoCompositeOp,
|
9
|
+
Magick::AddCompositeOp,
|
10
|
+
Magick::AtopCompositeOp,
|
11
|
+
Magick::BumpmapCompositeOp,
|
12
|
+
Magick::ClearCompositeOp,
|
13
|
+
Magick::ColorizeCompositeOp,
|
14
|
+
Magick::CopyBlueCompositeOp,
|
15
|
+
Magick::CopyCompositeOp,
|
16
|
+
Magick::CopyGreenCompositeOp,
|
17
|
+
Magick::CopyOpacityCompositeOp,
|
18
|
+
Magick::CopyRedCompositeOp,
|
19
|
+
Magick::CopyCyanCompositeOp,
|
20
|
+
Magick::CopyMagentaCompositeOp,
|
21
|
+
Magick::CopyYellowCompositeOp,
|
22
|
+
Magick::CopyBlackCompositeOp,
|
23
|
+
Magick::DarkenCompositeOp,
|
24
|
+
Magick::DifferenceCompositeOp,
|
25
|
+
Magick::DisplaceCompositeOp,
|
26
|
+
Magick::DissolveCompositeOp,
|
27
|
+
Magick::DstAtopCompositeOp,
|
28
|
+
Magick::DstCompositeOp,
|
29
|
+
Magick::DstInCompositeOp,
|
30
|
+
Magick::DstOutCompositeOp,
|
31
|
+
Magick::DstOverCompositeOp,
|
32
|
+
Magick::HueCompositeOp,
|
33
|
+
Magick::InCompositeOp,
|
34
|
+
Magick::LightenCompositeOp,
|
35
|
+
Magick::LuminizeCompositeOp,
|
36
|
+
Magick::MinusCompositeOp,
|
37
|
+
Magick::ModulateCompositeOp,
|
38
|
+
Magick::MultiplyCompositeOp,
|
39
|
+
Magick::OutCompositeOp,
|
40
|
+
Magick::OverCompositeOp,
|
41
|
+
Magick::OverlayCompositeOp,
|
42
|
+
Magick::PlusCompositeOp,
|
43
|
+
Magick::ReplaceCompositeOp,
|
44
|
+
Magick::SaturateCompositeOp,
|
45
|
+
Magick::ScreenCompositeOp,
|
46
|
+
Magick::SrcAtopCompositeOp,
|
47
|
+
Magick::SrcCompositeOp,
|
48
|
+
Magick::SrcInCompositeOp,
|
49
|
+
Magick::SrcOutCompositeOp,
|
50
|
+
Magick::SrcOverCompositeOp,
|
51
|
+
Magick::SubtractCompositeOp,
|
52
|
+
Magick::ThresholdCompositeOp,
|
53
|
+
Magick::XorCompositeOp,
|
54
|
+
Magick::BlendCompositeOp,
|
55
|
+
Magick::ColorBurnCompositeOp,
|
56
|
+
Magick::ColorDodgeCompositeOp,
|
57
|
+
Magick::ExclusionCompositeOp,
|
58
|
+
Magick::HardLightCompositeOp,
|
59
|
+
Magick::SoftLightCompositeOp
|
60
|
+
]
|
61
|
+
end
|
62
|
+
let(:gravity) do
|
63
|
+
[
|
64
|
+
Magick::NorthEastGravity,
|
65
|
+
Magick::EastGravity,
|
66
|
+
Magick::SouthWestGravity,
|
67
|
+
Magick::SouthGravity,
|
68
|
+
Magick::SouthEastGravity
|
69
|
+
]
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'raises an error given invalid arguments' do
|
73
|
+
expect { img1.composite }.to raise_error(ArgumentError)
|
74
|
+
expect { img1.composite(img2) }.to raise_error(ArgumentError)
|
75
|
+
expect do
|
76
|
+
img1.composite(img2, Magick::NorthWestGravity)
|
77
|
+
end.to raise_error(ArgumentError)
|
78
|
+
expect { img1.composite(2) }.to raise_error(ArgumentError)
|
79
|
+
expect { img1.composite(img2, 2) }.to raise_error(ArgumentError)
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'when given 3 arguments' do
|
83
|
+
it 'works when 2nd argument is a gravity' do
|
84
|
+
composite_ops.each do |op|
|
85
|
+
gravity.each do |grav|
|
86
|
+
expect { img1.composite(img2, grav, op) }.not_to raise_error
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'raises an error when 2nd argument is not a gravity' do
|
92
|
+
expect do
|
93
|
+
img1.composite(img2, 2, Magick::OverCompositeOp)
|
94
|
+
end.to raise_error(TypeError)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'when given 4 arguments' do
|
99
|
+
it 'works when 4th argument is a composite operator' do
|
100
|
+
# there are way too many CompositeOperators to test them all, so just try
|
101
|
+
# few representative ops
|
102
|
+
composite_ops.each do |op|
|
103
|
+
expect { img1.composite(img2, 0, 0, op) }.not_to raise_error
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'returns a new Magick::Image object' do
|
108
|
+
res = img1.composite(img2, 0, 0, Magick::OverCompositeOp)
|
109
|
+
expect(res).to be_instance_of(Magick::Image)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'raises an error when 4th argument is not a composite operator' do
|
113
|
+
expect { img1.composite(img2, 0, 0, 2) }.to raise_error(TypeError)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'when given 5 arguments' do
|
118
|
+
it 'works when 2nd argument is gravity and 5th is a composite operator' do
|
119
|
+
composite_ops.each do |op|
|
120
|
+
gravity.each do |grav|
|
121
|
+
expect { img1.composite(img2, grav, 0, 0, op) }.not_to raise_error
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'raises an error when 2nd argument is not a gravity' do
|
127
|
+
expect do
|
128
|
+
img1.composite(img2, 0, 0, 2, Magick::OverCompositeOp)
|
129
|
+
end.to raise_error(TypeError)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'raises an error when the image has been destroyed' do
|
134
|
+
img2.destroy!
|
135
|
+
expect do
|
136
|
+
img1.composite(img2, Magick::CenterGravity, Magick::OverCompositeOp)
|
137
|
+
end.to raise_error(Magick::DestroyedImageError)
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|