watir_visual_diff 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +36 -0
- data/.rspec +2 -0
- data/.rubocop.yml +48 -0
- data/.travis.yml +14 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +116 -0
- data/Rakefile +10 -0
- data/bin/console +7 -0
- data/bin/setup +6 -0
- data/examples/performance.rb +42 -0
- data/lib/watir_visual_diff/color_methods.rb +23 -0
- data/lib/watir_visual_diff/image.rb +60 -0
- data/lib/watir_visual_diff/matcher.rb +51 -0
- data/lib/watir_visual_diff/modes/base.rb +63 -0
- data/lib/watir_visual_diff/modes/delta.rb +54 -0
- data/lib/watir_visual_diff/modes/grayscale.rb +49 -0
- data/lib/watir_visual_diff/modes/rgb.rb +34 -0
- data/lib/watir_visual_diff/modes.rb +7 -0
- data/lib/watir_visual_diff/rectangle.rb +31 -0
- data/lib/watir_visual_diff/result.rb +23 -0
- data/lib/watir_visual_diff/version.rb +3 -0
- data/lib/watir_visual_diff.rb +14 -0
- data/spec/fixtures/a.png +0 -0
- data/spec/fixtures/a1.png +0 -0
- data/spec/fixtures/b.png +0 -0
- data/spec/fixtures/darker.png +0 -0
- data/spec/fixtures/delta_diff.png +0 -0
- data/spec/fixtures/exclude.png +0 -0
- data/spec/fixtures/grayscale_diff.png +0 -0
- data/spec/fixtures/include.png +0 -0
- data/spec/fixtures/rgb_diff.png +0 -0
- data/spec/fixtures/small.png +0 -0
- data/spec/fixtures/very_small.png +0 -0
- data/spec/image_spec.rb +11 -0
- data/spec/imatcher_spec.rb +7 -0
- data/spec/integrations/delta_spec.rb +51 -0
- data/spec/integrations/grayscale_spec.rb +71 -0
- data/spec/integrations/rgb_spec.rb +51 -0
- data/spec/matcher_spec.rb +77 -0
- data/spec/rectangle_spec.rb +37 -0
- data/spec/spec_helper.rb +14 -0
- data/watir_visual_diff.gemspec +21 -0
- metadata +129 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4b59144d0fc2d9d5c3267367ab8c212e10cc2a57
|
4
|
+
data.tar.gz: f8b9b36c9bef41891938a8084d71c1d6bd3e8ce8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 60d535c8e4e962fc48846c9b0212059bd2dc73a5eb7ae312ed6969a7f17bc4537a686360ffccbe47535c0fb5d733d13529f21c2c7c28768fecfad14e65d905cf
|
7
|
+
data.tar.gz: af3dc2a60f7db4226af17676620595f3b31d9b2f4c911b141fd2d94c4369484fa6e088784e40a782fe7ef7078449f5db1e8095f0f8f61f06ff728991eccfab6c
|
data/.gitignore
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Numerous always-ignore extensions
|
2
|
+
*.diff
|
3
|
+
*.err
|
4
|
+
*.orig
|
5
|
+
*.log
|
6
|
+
*.rej
|
7
|
+
*.swo
|
8
|
+
*.swp
|
9
|
+
*.vi
|
10
|
+
*~
|
11
|
+
*.sass-cache
|
12
|
+
*.iml
|
13
|
+
.idea/
|
14
|
+
|
15
|
+
# Sublime
|
16
|
+
*.sublime-project
|
17
|
+
*.sublime-workspace
|
18
|
+
|
19
|
+
# OS or Editor folders
|
20
|
+
.DS_Store
|
21
|
+
.cache
|
22
|
+
.project
|
23
|
+
.settings
|
24
|
+
.tmproj
|
25
|
+
Thumbs.db
|
26
|
+
*.gem
|
27
|
+
|
28
|
+
/.bundle/
|
29
|
+
/.yardoc
|
30
|
+
/Gemfile.lock
|
31
|
+
/_yardoc/
|
32
|
+
/coverage/
|
33
|
+
/doc/
|
34
|
+
/pkg/
|
35
|
+
/spec/reports/
|
36
|
+
/tmp/
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
AllCops:
|
2
|
+
# Include gemspec and Rakefile
|
3
|
+
Include:
|
4
|
+
- 'lib/**/*.rb'
|
5
|
+
- 'lib/**/*.rake'
|
6
|
+
- 'spec/**/*.rb'
|
7
|
+
Exclude:
|
8
|
+
- 'bin/**/*'
|
9
|
+
- 'spec/dummy/**/*'
|
10
|
+
Rails:
|
11
|
+
Enabled: false
|
12
|
+
DisplayCopNames: true
|
13
|
+
StyleGuideCopsOnly: false
|
14
|
+
|
15
|
+
Style/AccessorMethodName:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
Style/TrivialAccessors:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Style/Documentation:
|
22
|
+
Exclude:
|
23
|
+
- 'spec/**/*.rb'
|
24
|
+
|
25
|
+
Style/StringLiterals:
|
26
|
+
Enabled: false
|
27
|
+
|
28
|
+
Style/SpaceInsideStringInterpolation:
|
29
|
+
EnforcedStyle: no_space
|
30
|
+
|
31
|
+
Style/BlockDelimiters:
|
32
|
+
Exclude:
|
33
|
+
- 'spec/**/*.rb'
|
34
|
+
|
35
|
+
Style/ParallelAssignment:
|
36
|
+
Enabled: false
|
37
|
+
|
38
|
+
Lint/AmbiguousRegexpLiteral:
|
39
|
+
Enabled: false
|
40
|
+
|
41
|
+
Metrics/MethodLength:
|
42
|
+
Exclude:
|
43
|
+
- 'spec/**/*.rb'
|
44
|
+
|
45
|
+
Metrics/LineLength:
|
46
|
+
max: 100
|
47
|
+
Exclude:
|
48
|
+
- 'spec/**/*.rb'
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Justin Commu
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
[](https://rubygems.org/gems/watir_visual_diff) [](https://travis-ci.org/teachbase/watir_visual_diff)
|
2
|
+
|
3
|
+
# WatirVisualDiff
|
4
|
+
|
5
|
+
Compare PNG images in pure Ruby (uses [ChunkyPNG](https://github.com/wvanbergen/chunky_png)) using different algorithms.
|
6
|
+
This is an utility library for image regression testing.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem 'watir_visual_diff'
|
14
|
+
```
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install watir_visual_diff
|
23
|
+
|
24
|
+
Additionally, you may want to install [oily_png](https://github.com/wvanbergen/oily_png) to improve performance when using MRI. Just install it globally or add to your Gemfile.
|
25
|
+
|
26
|
+
## Modes
|
27
|
+
|
28
|
+
WatirVisualDiff supports different ways (_modes_) of comparing images.
|
29
|
+
|
30
|
+
Source images used in examples:
|
31
|
+
|
32
|
+
<img src="https://raw.githubusercontent.com/teachbase/watir_visual_diff/master/spec/fixtures/a.png" width="300" />
|
33
|
+
<img src="https://raw.githubusercontent.com/teachbase/watir_visual_diff/master/spec/fixtures/b.png" width="300" />
|
34
|
+
|
35
|
+
### Base (RGB) mode
|
36
|
+
|
37
|
+
Compare pixels by values, resulting score is a ratio of unequal pixels.
|
38
|
+
Resulting diff represents per-channel difference.
|
39
|
+
|
40
|
+
<img src="https://raw.githubusercontent.com/teachbase/watir_visual_diff/master/spec/fixtures/rgb_diff.png" width="300" />
|
41
|
+
|
42
|
+
### Grayscale mode
|
43
|
+
|
44
|
+
Compare pixels as grayscale (by brightness and alpha), resulting score is a ratio of unequal pixels (with respect to provided tolerance).
|
45
|
+
|
46
|
+
Resulting diff contains grayscale version of the first image with different pixels highlighted in red and red bounding box.
|
47
|
+
|
48
|
+
<img src="https://raw.githubusercontent.com/teachbase/watir_visual_diff/master/spec/fixtures/grayscale_diff.png" width="300" />
|
49
|
+
|
50
|
+
### Delta
|
51
|
+
|
52
|
+
Compare pixels using [Delta E](https://en.wikipedia.org/wiki/Color_difference) distance.
|
53
|
+
Resulting diff contains grayscale version of the first image with different pixels highlighted in red (with respect to diff score).
|
54
|
+
|
55
|
+
<img src="https://raw.githubusercontent.com/teachbase/watir_visual_diff/master/spec/fixtures/delta_diff.png" width="300" />
|
56
|
+
|
57
|
+
## Usage
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
# create new matcher with default threshold equals to 0
|
61
|
+
# and base (RGB) mode
|
62
|
+
cmp = WatirVisualDiff::Matcher.new
|
63
|
+
cmp.mode #=> WatirVisualDiff::Modes::RGB
|
64
|
+
|
65
|
+
# create matcher with specific threshold
|
66
|
+
cmp = WatirVisualDiff::Matcher.new threshold: 0.05
|
67
|
+
cmp.threshold #=> 0.05
|
68
|
+
|
69
|
+
# create zero-tolerance grayscale matcher
|
70
|
+
cmp = WatirVisualDiff::Matcher.new mode: :grayscale, tolerance: 0
|
71
|
+
cmp.mode #=> WatirVisualDiff::Modes::Grayscale
|
72
|
+
|
73
|
+
res = cmp.compare(path_1, path_2)
|
74
|
+
res #=> WatirVisualDiff::Result
|
75
|
+
|
76
|
+
res.match? #=> true
|
77
|
+
|
78
|
+
res.score #=> 0.0
|
79
|
+
|
80
|
+
# Return diff image object
|
81
|
+
res.difference_image #=> WatirVisualDiff::Image
|
82
|
+
|
83
|
+
res.difference_image.save(new_path)
|
84
|
+
|
85
|
+
# without explicit matcher
|
86
|
+
res = WatirVisualDiff.compare(path_1, path_2, options)
|
87
|
+
|
88
|
+
# equals to
|
89
|
+
res = WatirVisualDiff::Matcher.new(options).compare(path_1, path_2)
|
90
|
+
|
91
|
+
```
|
92
|
+
|
93
|
+
## Excluding rectangle
|
94
|
+
|
95
|
+
<img src="https://raw.githubusercontent.com/teachbase/watir_visual_diff/master/spec/fixtures/a.png" width="300" />
|
96
|
+
<img src="https://raw.githubusercontent.com/teachbase/watir_visual_diff/master/spec/fixtures/a1.png" width="300" />
|
97
|
+
|
98
|
+
You can exclude rectangle from comparing by passing `:exclude_rect` to `compare`.
|
99
|
+
E.g., if `path_1` and `path_2` contain images above
|
100
|
+
```ruby
|
101
|
+
WatirVisualDiff.compare(path_1, path_2, exclude_rect: [200, 150, 275, 200]).match? # => true
|
102
|
+
```
|
103
|
+
`[200, 150, 275, 200]` is array of two vertices of rectangle -- (200, 150) is left-top vertex and (275, 200) is right-bottom.
|
104
|
+
|
105
|
+
## Including rectangle
|
106
|
+
|
107
|
+
You can set bounds of comparing by passing `:include_rect` to `compare` with array similar to previous example
|
108
|
+
|
109
|
+
## Contributing
|
110
|
+
|
111
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/teachbase/watir_visual_diff.
|
112
|
+
|
113
|
+
## License
|
114
|
+
|
115
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
116
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
data/bin/setup
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'benchmark/ips'
|
3
|
+
require 'watir_visual_diff'
|
4
|
+
|
5
|
+
a = WatirVisualDiff::Image.from_file(File.expand_path('../../spec/fixtures/a.png', __FILE__))
|
6
|
+
b = WatirVisualDiff::Image.from_file(File.expand_path('../../spec/fixtures/a.png', __FILE__))
|
7
|
+
|
8
|
+
rgb = WatirVisualDiff::Matcher.new
|
9
|
+
grayscale = WatirVisualDiff::Matcher.new mode: :grayscale
|
10
|
+
delta = WatirVisualDiff::Matcher.new mode: :delta
|
11
|
+
|
12
|
+
Benchmark.ips do |x|
|
13
|
+
x.report 'RGB' do
|
14
|
+
rgb.compare(a, b)
|
15
|
+
end
|
16
|
+
|
17
|
+
x.report 'Grayscale' do
|
18
|
+
grayscale.compare(a, b)
|
19
|
+
end
|
20
|
+
|
21
|
+
x.report 'Delta E' do
|
22
|
+
delta.compare(a, b)
|
23
|
+
end
|
24
|
+
|
25
|
+
x.compare!
|
26
|
+
end
|
27
|
+
|
28
|
+
Benchmark.ips do |x|
|
29
|
+
x.report 'RGB' do
|
30
|
+
rgb.compare(a, b).difference_image
|
31
|
+
end
|
32
|
+
|
33
|
+
x.report 'Grayscale' do
|
34
|
+
grayscale.compare(a, b).difference_image
|
35
|
+
end
|
36
|
+
|
37
|
+
x.report 'Delta E' do
|
38
|
+
delta.compare(a, b).difference_image
|
39
|
+
end
|
40
|
+
|
41
|
+
x.compare!
|
42
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "oily_png"
|
2
|
+
|
3
|
+
module WatirVisualDiff
|
4
|
+
module ColorMethods # :nodoc:
|
5
|
+
include ChunkyPNG::Color
|
6
|
+
|
7
|
+
def brightness(a)
|
8
|
+
0.3 * r(a) + 0.59 * g(a) + 0.11 * b(a)
|
9
|
+
end
|
10
|
+
|
11
|
+
def red
|
12
|
+
rgb(255, 0, 0)
|
13
|
+
end
|
14
|
+
|
15
|
+
def green
|
16
|
+
rgb(0, 255, 0)
|
17
|
+
end
|
18
|
+
|
19
|
+
def blue
|
20
|
+
rgb(0, 0, 255)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'watir_visual_diff/color_methods'
|
2
|
+
|
3
|
+
module WatirVisualDiff
|
4
|
+
# Extend ChunkyPNG::Image with some methods.
|
5
|
+
class Image < ChunkyPNG::Image
|
6
|
+
include ColorMethods
|
7
|
+
|
8
|
+
def each_pixel
|
9
|
+
height.times do |y|
|
10
|
+
row(y).each_with_index do |pixel, x|
|
11
|
+
yield(pixel, x, y)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def compare_each_pixel(image, area: nil)
|
17
|
+
area = bounding_rect if area.nil?
|
18
|
+
(area.top..area.bot).each do |y|
|
19
|
+
range = (area.left..area.right)
|
20
|
+
next if image.row(y).slice(range) == row(y).slice(range)
|
21
|
+
(area.left..area.right).each do |x|
|
22
|
+
yield(self[x, y], image[x, y], x, y)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_grayscale
|
28
|
+
each_pixel do |pixel, x, y|
|
29
|
+
self[x, y] = grayscale(brightness(pixel).round)
|
30
|
+
end
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def with_alpha(value)
|
35
|
+
each_pixel do |pixel, x, y|
|
36
|
+
self[x, y] = rgba(r(pixel), g(pixel), b(pixel), value)
|
37
|
+
end
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def sizes_match?(image)
|
42
|
+
[width, height] == [image.width, image.height]
|
43
|
+
end
|
44
|
+
|
45
|
+
def inspect
|
46
|
+
"Image:#{object_id}<#{width}x#{height}>"
|
47
|
+
end
|
48
|
+
|
49
|
+
def highlight_rectangle(rect, color = :red)
|
50
|
+
fail ArgumentError, "Undefined color: #{color}" unless respond_to?(color)
|
51
|
+
return self if rect.nil?
|
52
|
+
rect(*rect.bounds, send(color))
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
def bounding_rect
|
57
|
+
Rectangle.new(0, 0, width - 1, height - 1)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module WatirVisualDiff
|
2
|
+
# Matcher contains information about compare mode
|
3
|
+
class Matcher
|
4
|
+
require 'watir_visual_diff/image'
|
5
|
+
require 'watir_visual_diff/result'
|
6
|
+
require 'watir_visual_diff/modes'
|
7
|
+
|
8
|
+
MODES = {
|
9
|
+
rgb: 'RGB',
|
10
|
+
delta: 'Delta',
|
11
|
+
grayscale: 'Grayscale'
|
12
|
+
}.freeze
|
13
|
+
|
14
|
+
attr_reader :threshold, :mode
|
15
|
+
|
16
|
+
def initialize(options = {})
|
17
|
+
mode_type = options.delete(:mode) || :rgb
|
18
|
+
fail ArgumentError, "Undefined mode: #{ mode_type }" unless MODES.keys.include?(mode_type)
|
19
|
+
@mode = Modes.const_get(MODES[mode_type]).new(options)
|
20
|
+
end
|
21
|
+
|
22
|
+
def compare(a, b)
|
23
|
+
a = Image.from_file(a) unless a.is_a?(Image)
|
24
|
+
b = Image.from_file(b) unless b.is_a?(Image)
|
25
|
+
|
26
|
+
fail SizesMismatchError,
|
27
|
+
"Size mismatch: first image size: " \
|
28
|
+
"#{a.width}x#{a.height}, " \
|
29
|
+
"second image size: " \
|
30
|
+
"#{b.width}x#{b.height}" unless a.sizes_match?(b)
|
31
|
+
|
32
|
+
image_area = Rectangle.new(0, 0, a.width - 1, a.height - 1)
|
33
|
+
|
34
|
+
unless mode.exclude_rect.nil?
|
35
|
+
fail ArgumentError,
|
36
|
+
"Bounds must be in image" unless image_area.contains?(mode.exclude_rect)
|
37
|
+
end
|
38
|
+
|
39
|
+
unless mode.include_rect.nil?
|
40
|
+
fail ArgumentError,
|
41
|
+
"Bounds must be in image" unless image_area.contains?(mode.include_rect)
|
42
|
+
unless mode.exclude_rect.nil?
|
43
|
+
fail ArgumentError,
|
44
|
+
"Included area must contain excluded" unless mode.include_rect.contains?(mode.exclude_rect)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
mode.compare(a, b)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module WatirVisualDiff
|
2
|
+
module Modes
|
3
|
+
class Base # :nodoc:
|
4
|
+
require 'watir_visual_diff/rectangle'
|
5
|
+
include ColorMethods
|
6
|
+
|
7
|
+
attr_reader :result, :threshold, :bounds, :exclude_rect, :include_rect
|
8
|
+
|
9
|
+
def initialize(threshold: 0.0, exclude_rect: nil, include_rect: nil)
|
10
|
+
@include_rect = Rectangle.new(*include_rect) unless include_rect.nil?
|
11
|
+
@exclude_rect = Rectangle.new(*exclude_rect) unless exclude_rect.nil?
|
12
|
+
@threshold = threshold
|
13
|
+
@result = Result.new(self, threshold)
|
14
|
+
end
|
15
|
+
|
16
|
+
def compare(a, b)
|
17
|
+
result.image = a
|
18
|
+
@include_rect ||= a.bounding_rect
|
19
|
+
@bounds = Rectangle.new(*include_rect.bounds)
|
20
|
+
|
21
|
+
b.compare_each_pixel(a, area: include_rect) do |b_pixel, a_pixel, x, y|
|
22
|
+
next if pixels_equal?(b_pixel, a_pixel)
|
23
|
+
next if !exclude_rect.nil? && exclude_rect.contains_point?(x, y)
|
24
|
+
update_result(b_pixel, a_pixel, x, y)
|
25
|
+
end
|
26
|
+
|
27
|
+
result.score = score
|
28
|
+
result
|
29
|
+
end
|
30
|
+
|
31
|
+
def diff(bg, diff)
|
32
|
+
diff_image = background(bg).highlight_rectangle(exclude_rect, :blue)
|
33
|
+
diff.each do |pixels_pair|
|
34
|
+
pixels_diff(diff_image, *pixels_pair)
|
35
|
+
end
|
36
|
+
create_diff_image(bg, diff_image).
|
37
|
+
highlight_rectangle(bounds).
|
38
|
+
highlight_rectangle(include_rect, :green)
|
39
|
+
end
|
40
|
+
|
41
|
+
def score
|
42
|
+
result.diff.length.to_f / area
|
43
|
+
end
|
44
|
+
|
45
|
+
def update_result(*_args, x, y)
|
46
|
+
update_bounds(x, y)
|
47
|
+
end
|
48
|
+
|
49
|
+
def update_bounds(x, y)
|
50
|
+
bounds.left = [x, bounds.left].max
|
51
|
+
bounds.top = [y, bounds.top].max
|
52
|
+
bounds.right = [x, bounds.right].min
|
53
|
+
bounds.bot = [y, bounds.bot].min
|
54
|
+
end
|
55
|
+
|
56
|
+
def area
|
57
|
+
area = include_rect.area
|
58
|
+
return area if exclude_rect.nil?
|
59
|
+
area - exclude_rect.area
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module WatirVisualDiff
|
2
|
+
module Modes # :nodoc:
|
3
|
+
require 'watir_visual_diff/modes/base'
|
4
|
+
|
5
|
+
# Compare pixels using Delta E distance.
|
6
|
+
class Delta < Base
|
7
|
+
attr_reader :tolerance
|
8
|
+
|
9
|
+
def initialize(options)
|
10
|
+
@tolerance = options.delete(:tolerance) || 0.01
|
11
|
+
@delta_score = 0.0
|
12
|
+
super(options)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def pixels_equal?(a, b)
|
18
|
+
a == b
|
19
|
+
end
|
20
|
+
|
21
|
+
def update_result(a, b, x, y)
|
22
|
+
d = euclid(a, b) / (MAX * Math.sqrt(3))
|
23
|
+
return if d <= tolerance
|
24
|
+
@result.diff << [a, b, x, y, d]
|
25
|
+
@delta_score += d
|
26
|
+
super
|
27
|
+
end
|
28
|
+
|
29
|
+
def background(bg)
|
30
|
+
Image.new(bg.width, bg.height, WHITE).with_alpha(0)
|
31
|
+
end
|
32
|
+
|
33
|
+
def euclid(a, b)
|
34
|
+
Math.sqrt(
|
35
|
+
(r(a) - r(b))**2 +
|
36
|
+
(g(a) - g(b))**2 +
|
37
|
+
(b(a) - b(b))**2
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def create_diff_image(bg, diff_image)
|
42
|
+
bg.to_grayscale.compose!(diff_image, 0, 0)
|
43
|
+
end
|
44
|
+
|
45
|
+
def pixels_diff(d, *_args, x, y, a)
|
46
|
+
d[x, y] = rgba(MAX, 0, 0, (a * MAX).round)
|
47
|
+
end
|
48
|
+
|
49
|
+
def score
|
50
|
+
@delta_score / area
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module WatirVisualDiff
|
2
|
+
module Modes # :nodoc:
|
3
|
+
require 'watir_visual_diff/modes/base'
|
4
|
+
|
5
|
+
# Compare pixels by alpha and brightness.
|
6
|
+
#
|
7
|
+
# Options:
|
8
|
+
# - tolerance - defines the maximum allowed difference for alpha/brightness
|
9
|
+
# (default value is 16)
|
10
|
+
class Grayscale < Base
|
11
|
+
DEFAULT_TOLERANCE = 16
|
12
|
+
|
13
|
+
attr_reader :tolerance
|
14
|
+
|
15
|
+
def initialize(options)
|
16
|
+
@tolerance = options.delete(:tolerance) || DEFAULT_TOLERANCE
|
17
|
+
super(options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def pixels_equal?(a, b)
|
21
|
+
alpha = color_similar?(a(a), a(b))
|
22
|
+
brightness = color_similar?(brightness(a), brightness(b))
|
23
|
+
brightness && alpha
|
24
|
+
end
|
25
|
+
|
26
|
+
def update_result(a, b, x, y)
|
27
|
+
super
|
28
|
+
@result.diff << [a, b, x, y]
|
29
|
+
end
|
30
|
+
|
31
|
+
def background(bg)
|
32
|
+
bg.to_grayscale
|
33
|
+
end
|
34
|
+
|
35
|
+
def pixels_diff(d, _a, _b, x, y)
|
36
|
+
d[x, y] = rgb(255, 0, 0)
|
37
|
+
end
|
38
|
+
|
39
|
+
def create_diff_image(_bg, diff_image)
|
40
|
+
diff_image
|
41
|
+
end
|
42
|
+
|
43
|
+
def color_similar?(a, b)
|
44
|
+
d = (a - b).abs
|
45
|
+
d <= tolerance
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module WatirVisualDiff
|
2
|
+
module Modes # :nodoc:
|
3
|
+
require 'watir_visual_diff/modes/base'
|
4
|
+
|
5
|
+
# Compare pixels by values.
|
6
|
+
# Resulting image contains per-channel differences.
|
7
|
+
class RGB < Base
|
8
|
+
def pixels_equal?(a, b)
|
9
|
+
a == b
|
10
|
+
end
|
11
|
+
|
12
|
+
def update_result(a, b, x, y)
|
13
|
+
super
|
14
|
+
@result.diff << [a, b, x, y]
|
15
|
+
end
|
16
|
+
|
17
|
+
def background(bg)
|
18
|
+
Image.new(bg.width, bg.height, BLACK)
|
19
|
+
end
|
20
|
+
|
21
|
+
def create_diff_image(_bg, diff_image)
|
22
|
+
diff_image
|
23
|
+
end
|
24
|
+
|
25
|
+
def pixels_diff(d, a, b, x, y)
|
26
|
+
d[x, y] = rgb(
|
27
|
+
(r(a) - r(b)).abs,
|
28
|
+
(g(a) - g(b)).abs,
|
29
|
+
(b(a) - b(b)).abs
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module WatirVisualDiff
|
2
|
+
class Rectangle
|
3
|
+
attr_accessor :left, :top, :right, :bot
|
4
|
+
|
5
|
+
def initialize(l, t, r, b)
|
6
|
+
@left = l
|
7
|
+
@top = t
|
8
|
+
@right = r
|
9
|
+
@bot = b
|
10
|
+
end
|
11
|
+
|
12
|
+
def area
|
13
|
+
(right - left + 1) * (bot - top + 1)
|
14
|
+
end
|
15
|
+
|
16
|
+
def contains?(rect)
|
17
|
+
(left <= rect.left) &&
|
18
|
+
(right >= rect.right) &&
|
19
|
+
(top <= rect.top) &&
|
20
|
+
(bot >= rect.bot)
|
21
|
+
end
|
22
|
+
|
23
|
+
def bounds
|
24
|
+
[left, top, right, bot]
|
25
|
+
end
|
26
|
+
|
27
|
+
def contains_point?(x, y)
|
28
|
+
x.between?(left, right) && y.between?(top, bot)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module WatirVisualDiff
|
2
|
+
# Object containing comparison score and diff image
|
3
|
+
class Result
|
4
|
+
attr_accessor :score, :image
|
5
|
+
attr_reader :diff, :mode, :threshold
|
6
|
+
|
7
|
+
def initialize(mode, threshold)
|
8
|
+
@score = 0.0
|
9
|
+
@diff = []
|
10
|
+
@threshold = threshold
|
11
|
+
@mode = mode
|
12
|
+
end
|
13
|
+
|
14
|
+
def difference_image
|
15
|
+
@diff_image ||= mode.diff(image, diff)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns true iff score less or equals to threshold
|
19
|
+
def match?
|
20
|
+
score <= threshold
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "watir_visual_diff/version"
|
2
|
+
|
3
|
+
# Compare PNG images using different algorithms
|
4
|
+
module WatirVisualDiff
|
5
|
+
class SizesMismatchError < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'watir_visual_diff/matcher'
|
9
|
+
require 'watir_visual_diff/color_methods'
|
10
|
+
|
11
|
+
def self.compare(path_a, path_b, options = {})
|
12
|
+
Matcher.new(options).compare(path_a, path_b)
|
13
|
+
end
|
14
|
+
end
|
data/spec/fixtures/a.png
ADDED
Binary file
|
Binary file
|
data/spec/fixtures/b.png
ADDED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/spec/image_spec.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe WatirVisualDiff::Image do
|
4
|
+
describe "highlight_rectangle" do
|
5
|
+
let(:image) { described_class.new(10, 10, described_class::BLACK) }
|
6
|
+
let(:rect) { WatirVisualDiff::Rectangle.new(0, 0, 1, 1) }
|
7
|
+
subject { image.highlight_rectangle(rect, :deep_purple) }
|
8
|
+
|
9
|
+
it { expect { subject }.to raise_error(ArgumentError) }
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe WatirVisualDiff::Modes::Delta do
|
4
|
+
let(:path_1) { image_path "a" }
|
5
|
+
let(:path_2) { image_path "darker" }
|
6
|
+
subject { WatirVisualDiff.compare(path_1, path_2, options) }
|
7
|
+
|
8
|
+
let(:options) { { mode: :delta } }
|
9
|
+
|
10
|
+
context "with darker image" do
|
11
|
+
it "score around 0.075" do
|
12
|
+
expect(subject.score).to be_within(0.005).of(0.075)
|
13
|
+
end
|
14
|
+
|
15
|
+
context "with custom threshold" do
|
16
|
+
subject { WatirVisualDiff.compare(path_1, path_2, options).match? }
|
17
|
+
|
18
|
+
context "below score" do
|
19
|
+
let(:options) { { mode: :delta, threshold: 0.01 } }
|
20
|
+
|
21
|
+
it { expect(subject).to be_falsey }
|
22
|
+
end
|
23
|
+
|
24
|
+
context "above score" do
|
25
|
+
let(:options) { { mode: :delta, threshold: 0.1 } }
|
26
|
+
|
27
|
+
it { expect(subject).to be_truthy }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "with different images" do
|
33
|
+
let(:path_2) { image_path "b" }
|
34
|
+
|
35
|
+
it "score around 0.0046" do
|
36
|
+
expect(subject.score).to be_within(0.0001).of(0.0046)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "creates correct difference image" do
|
40
|
+
expect(subject.difference_image).to eq(WatirVisualDiff::Image.from_file(image_path("delta_diff")))
|
41
|
+
end
|
42
|
+
|
43
|
+
context "with high tolerance" do
|
44
|
+
let(:options) { { mode: :delta, tolerance: 0.1 } }
|
45
|
+
|
46
|
+
it "score around 0.0038" do
|
47
|
+
expect(subject.score).to be_within(0.0001).of(0.0038)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe WatirVisualDiff::Modes::Grayscale do
|
4
|
+
let(:path_1) { image_path "a" }
|
5
|
+
let(:path_2) { image_path "darker" }
|
6
|
+
subject { WatirVisualDiff.compare(path_1, path_2, options) }
|
7
|
+
|
8
|
+
let(:options) { { mode: :grayscale } }
|
9
|
+
|
10
|
+
context "darker image" do
|
11
|
+
it "score around 0.95" do
|
12
|
+
expect(subject.score).to be_within(0.05).of(0.95)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "different images" do
|
17
|
+
let(:path_2) { image_path "b" }
|
18
|
+
|
19
|
+
it "score around 0.005" do
|
20
|
+
expect(subject.score).to be_within(0.001).of(0.005)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "creates correct difference image" do
|
24
|
+
expect(subject.difference_image).to eq(WatirVisualDiff::Image.from_file(image_path("grayscale_diff")))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "with zero tolerance" do
|
29
|
+
let(:options) { { mode: :grayscale, tolerance: 0 } }
|
30
|
+
|
31
|
+
context "darker image" do
|
32
|
+
it "score equals to 1" do
|
33
|
+
expect(subject.score).to eq 1.0
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "different image" do
|
38
|
+
let(:path_2) { image_path "b" }
|
39
|
+
|
40
|
+
it "score around 0.016" do
|
41
|
+
expect(subject.score).to be_within(0.001).of(0.016)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "equal image" do
|
46
|
+
let(:path_2) { image_path "a" }
|
47
|
+
|
48
|
+
it "score equals to 0" do
|
49
|
+
expect(subject.score).to eq 0
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "with small tolerance" do
|
55
|
+
let(:options) { { mode: :grayscale, tolerance: 8 } }
|
56
|
+
|
57
|
+
context "darker image" do
|
58
|
+
it "score around 0.96" do
|
59
|
+
expect(subject.score).to be_within(0.005).of(0.96)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "different image" do
|
64
|
+
let(:path_2) { image_path "b" }
|
65
|
+
|
66
|
+
it "score around 0.006" do
|
67
|
+
expect(subject.score).to be_within(0.0005).of(0.006)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe WatirVisualDiff::Modes::RGB do
|
4
|
+
let(:path_1) { image_path "a" }
|
5
|
+
let(:path_2) { image_path "darker" }
|
6
|
+
subject { WatirVisualDiff.compare(path_1, path_2, options) }
|
7
|
+
let(:options) { {} }
|
8
|
+
|
9
|
+
context "with darker" do
|
10
|
+
it "score equals to 1" do
|
11
|
+
expect(subject.score).to eq 1
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "with different images" do
|
16
|
+
let(:path_2) { image_path "b" }
|
17
|
+
|
18
|
+
it "score around 0.016" do
|
19
|
+
expect(subject.score).to be_within(0.001).of(0.016)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "creates correct difference image" do
|
23
|
+
expect(subject.difference_image).to eq(WatirVisualDiff::Image.from_file(image_path("rgb_diff")))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "exclude rect" do
|
28
|
+
let(:options) { { exclude_rect: [200, 150, 275, 200] } }
|
29
|
+
let(:path_2) { image_path "a1" }
|
30
|
+
it { expect(subject.difference_image).to eq WatirVisualDiff::Image.from_file(image_path("exclude")) }
|
31
|
+
it { expect(subject.score).to eq 0 }
|
32
|
+
|
33
|
+
context "calculates score correctly" do
|
34
|
+
let(:path_2) { image_path "darker" }
|
35
|
+
|
36
|
+
it { expect(subject.score).to eq 1 }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "include rect" do
|
41
|
+
let(:options) { { include_rect: [0, 0, 100, 100] } }
|
42
|
+
let(:path_2) { image_path "a1" }
|
43
|
+
it { expect(subject.difference_image).to eq WatirVisualDiff::Image.from_file(image_path("include")) }
|
44
|
+
it { expect(subject.score).to eq 0 }
|
45
|
+
|
46
|
+
context "calculates score correctly" do
|
47
|
+
let(:path_2) { image_path "darker" }
|
48
|
+
it { expect(subject.score).to eq 1 }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe WatirVisualDiff::Matcher do
|
4
|
+
describe "new" do
|
5
|
+
subject { WatirVisualDiff::Matcher.new(options) }
|
6
|
+
|
7
|
+
context "without options" do
|
8
|
+
let(:options) { {} }
|
9
|
+
|
10
|
+
it { expect(subject.mode.threshold).to eq 0 }
|
11
|
+
it { expect(subject.mode).to be_a WatirVisualDiff::Modes::RGB }
|
12
|
+
end
|
13
|
+
|
14
|
+
context "with custom threshold" do
|
15
|
+
let(:options) { { threshold: 0.1 } }
|
16
|
+
|
17
|
+
it { expect(subject.mode.threshold).to eq 0.1 }
|
18
|
+
end
|
19
|
+
|
20
|
+
context "with custom options" do
|
21
|
+
let(:options) { { mode: :grayscale, tolerance: 0 } }
|
22
|
+
|
23
|
+
it { expect(subject.mode.tolerance).to eq 0 }
|
24
|
+
end
|
25
|
+
|
26
|
+
context "with custom mode" do
|
27
|
+
let(:options) { { mode: :delta } }
|
28
|
+
|
29
|
+
it { expect(subject.mode).to be_a WatirVisualDiff::Modes::Delta }
|
30
|
+
end
|
31
|
+
|
32
|
+
context "with undefined mode" do
|
33
|
+
let(:options) { { mode: :gamma } }
|
34
|
+
|
35
|
+
it { expect { subject }.to raise_error(ArgumentError) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "compare" do
|
40
|
+
let(:path_1) { image_path "very_small" }
|
41
|
+
let(:path_2) { image_path "very_small" }
|
42
|
+
let(:options) { {} }
|
43
|
+
subject { WatirVisualDiff.compare(path_1, path_2, options) }
|
44
|
+
|
45
|
+
it { expect(subject).to be_a WatirVisualDiff::Result }
|
46
|
+
|
47
|
+
context "when sizes mismatch" do
|
48
|
+
let(:path_2) { image_path "small" }
|
49
|
+
it { expect { subject }.to raise_error WatirVisualDiff::SizesMismatchError }
|
50
|
+
end
|
51
|
+
|
52
|
+
context "with negative exclude rect bounds" do
|
53
|
+
let(:options) { { exclude_rect: [-1, -1, -1, -1] } }
|
54
|
+
it { expect { subject }.to raise_error ArgumentError }
|
55
|
+
end
|
56
|
+
|
57
|
+
context "with big exclude rect bounds" do
|
58
|
+
let(:options) { { exclude_rect: [100, 100, 100, 100] } }
|
59
|
+
it { expect { subject }.to raise_error ArgumentError }
|
60
|
+
end
|
61
|
+
|
62
|
+
context "with negative include rect bounds" do
|
63
|
+
let(:options) { { include_rect: [-1, -1, -1, -1] } }
|
64
|
+
it { expect { subject }.to raise_error ArgumentError }
|
65
|
+
end
|
66
|
+
|
67
|
+
context "with big include rect bounds" do
|
68
|
+
let(:options) { { include_rect: [100, 100, 100, 100] } }
|
69
|
+
it { expect { subject }.to raise_error ArgumentError }
|
70
|
+
end
|
71
|
+
|
72
|
+
context "with wrong include and exclude rects combination" do
|
73
|
+
let(:options) { { include_rect: [1, 1, 2, 2], exclude_rect: [0, 0, 1, 1] } }
|
74
|
+
it { expect { subject }.to raise_error ArgumentError }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe WatirVisualDiff::Rectangle do
|
4
|
+
let(:rect) { described_class.new(0, 0, 9, 9) }
|
5
|
+
|
6
|
+
describe 'area' do
|
7
|
+
subject { rect.area }
|
8
|
+
|
9
|
+
it { expect(subject).to eq 100 }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "contains?" do
|
13
|
+
let(:rect2) { described_class.new(1, 1, 8, 8) }
|
14
|
+
subject { rect.contains?(rect2) }
|
15
|
+
|
16
|
+
it { expect(subject).to be_truthy }
|
17
|
+
|
18
|
+
context "when does not contain" do
|
19
|
+
let(:rect2) { described_class.new(2, 2, 10, 10) }
|
20
|
+
|
21
|
+
it { expect(subject).to be_falsey }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "contains_point?" do
|
26
|
+
let(:point) { [5, 5] }
|
27
|
+
subject { rect.contains_point?(*point) }
|
28
|
+
|
29
|
+
it { expect(subject).to be_truthy }
|
30
|
+
|
31
|
+
context "when does not contain" do
|
32
|
+
let(:point) { [10, 10] }
|
33
|
+
|
34
|
+
it { expect(subject).to be_falsey }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
|
3
|
+
require 'rspec'
|
4
|
+
require 'watir_visual_diff'
|
5
|
+
|
6
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.mock_with :rspec
|
10
|
+
end
|
11
|
+
|
12
|
+
def image_path(name)
|
13
|
+
"#{File.dirname(__FILE__)}/fixtures/#{name}.png"
|
14
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
require 'watir_visual_diff/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |spec|
|
5
|
+
spec.name = "watir_visual_diff"
|
6
|
+
spec.version = WatirVisualDiff::VERSION
|
7
|
+
spec.authors = ["Justin Commu"]
|
8
|
+
spec.email = ["jcommu@gmail.com"]
|
9
|
+
spec.summary = "Image comparison library for Watir"
|
10
|
+
spec.description = "Image comparison libray for Watir built on top of OilyPNG"
|
11
|
+
spec.homepage = "https://github.com/automation-wizards/watir_visual_diff"
|
12
|
+
spec.license = "MIT"
|
13
|
+
|
14
|
+
spec.files = `git ls-files`.split($/)
|
15
|
+
spec.require_paths = ["lib"]
|
16
|
+
|
17
|
+
spec.add_dependency "oily_png", "~> 1.2.1"
|
18
|
+
|
19
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
20
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: watir_visual_diff
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Justin Commu
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-03-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: oily_png
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.2.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.2.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description: Image comparison libray for Watir built on top of OilyPNG
|
56
|
+
email:
|
57
|
+
- jcommu@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- ".rspec"
|
64
|
+
- ".rubocop.yml"
|
65
|
+
- ".travis.yml"
|
66
|
+
- Gemfile
|
67
|
+
- LICENSE.txt
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
70
|
+
- bin/console
|
71
|
+
- bin/setup
|
72
|
+
- examples/performance.rb
|
73
|
+
- lib/watir_visual_diff.rb
|
74
|
+
- lib/watir_visual_diff/color_methods.rb
|
75
|
+
- lib/watir_visual_diff/image.rb
|
76
|
+
- lib/watir_visual_diff/matcher.rb
|
77
|
+
- lib/watir_visual_diff/modes.rb
|
78
|
+
- lib/watir_visual_diff/modes/base.rb
|
79
|
+
- lib/watir_visual_diff/modes/delta.rb
|
80
|
+
- lib/watir_visual_diff/modes/grayscale.rb
|
81
|
+
- lib/watir_visual_diff/modes/rgb.rb
|
82
|
+
- lib/watir_visual_diff/rectangle.rb
|
83
|
+
- lib/watir_visual_diff/result.rb
|
84
|
+
- lib/watir_visual_diff/version.rb
|
85
|
+
- spec/fixtures/a.png
|
86
|
+
- spec/fixtures/a1.png
|
87
|
+
- spec/fixtures/b.png
|
88
|
+
- spec/fixtures/darker.png
|
89
|
+
- spec/fixtures/delta_diff.png
|
90
|
+
- spec/fixtures/exclude.png
|
91
|
+
- spec/fixtures/grayscale_diff.png
|
92
|
+
- spec/fixtures/include.png
|
93
|
+
- spec/fixtures/rgb_diff.png
|
94
|
+
- spec/fixtures/small.png
|
95
|
+
- spec/fixtures/very_small.png
|
96
|
+
- spec/image_spec.rb
|
97
|
+
- spec/imatcher_spec.rb
|
98
|
+
- spec/integrations/delta_spec.rb
|
99
|
+
- spec/integrations/grayscale_spec.rb
|
100
|
+
- spec/integrations/rgb_spec.rb
|
101
|
+
- spec/matcher_spec.rb
|
102
|
+
- spec/rectangle_spec.rb
|
103
|
+
- spec/spec_helper.rb
|
104
|
+
- watir_visual_diff.gemspec
|
105
|
+
homepage: https://github.com/automation-wizards/watir_visual_diff
|
106
|
+
licenses:
|
107
|
+
- MIT
|
108
|
+
metadata: {}
|
109
|
+
post_install_message:
|
110
|
+
rdoc_options: []
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 2.6.7
|
126
|
+
signing_key:
|
127
|
+
specification_version: 4
|
128
|
+
summary: Image comparison library for Watir
|
129
|
+
test_files: []
|