Skip to content

Commit f0aea55

Browse files
committed
Introduce VIPs adapter for faster image processing
Ref: #15 * Allow to switch between chunky_png and vips version: global and per screenshot * Moved chunkypng to separate impl * Adds native vips implementation to find difference * Adds new strategies to find difference tollerance option and median filter size option * Setup Travis to install libvips with minimal required version
1 parent bd4a93e commit f0aea55

19 files changed

Lines changed: 1361 additions & 520 deletions

.rubocop.yml

Lines changed: 88 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ Style/HashTransformValues:
2121
Enabled: true
2222
# ODOT
2323

24-
Layout/ArgumentAlignment:
25-
EnforcedStyle: with_fixed_indentation
26-
IndentationWidth: 4
24+
#Layout/ArgumentAlignment:
25+
# EnforcedStyle: with_fixed_indentation
26+
# IndentationWidth: 4
2727

2828
Layout/HeredocIndentation:
29-
EnforcedStyle: active_support
29+
Enabled: true
3030

3131
Layout/LineLength:
3232
Max: 107
@@ -40,7 +40,8 @@ Layout/MultilineOperationIndentation:
4040

4141
Layout/ParameterAlignment:
4242
EnforcedStyle: with_fixed_indentation
43-
IndentationWidth: 4
43+
IndentationWidth: 2
44+
4445

4546
Lint/Debugger:
4647
Enabled: false
@@ -71,3 +72,85 @@ Style/NumericPredicate:
7172

7273
Style/SignalException:
7374
EnforcedStyle: semantic
75+
76+
# TODO: Review and enable
77+
Layout/EmptyLinesAroundAttributeAccessor:
78+
Enabled: false
79+
Layout/SpaceAroundMethodCallOperator:
80+
Enabled: false
81+
Lint/BinaryOperatorWithIdenticalOperands:
82+
Enabled: false
83+
Lint/DeprecatedOpenSSLConstant:
84+
Enabled: false
85+
Lint/DuplicateElsifCondition:
86+
Enabled: false
87+
Lint/DuplicateRescueException:
88+
Enabled: false
89+
Lint/EmptyConditionalBody:
90+
Enabled: false
91+
Lint/FloatComparison:
92+
Enabled: false
93+
Lint/MissingSuper:
94+
Enabled: false
95+
Lint/MixedRegexpCaptureTypes:
96+
Enabled: false
97+
Lint/SelfAssignment:
98+
Enabled: false
99+
Lint/TopLevelReturnWithArgument:
100+
Enabled: false
101+
Lint/OutOfRangeRegexpRef:
102+
Enabled: false
103+
Lint/UnreachableLoop:
104+
Enabled: false
105+
Style/AccessorGrouping:
106+
Enabled: false
107+
Style/ArrayCoercion:
108+
Enabled: false
109+
Style/BisectedAttrAccessor:
110+
Enabled: false
111+
Style/CaseLikeIf:
112+
Enabled: false
113+
Style/ExplicitBlockArgument:
114+
Enabled: false
115+
Style/ExponentialNotation:
116+
Enabled: false
117+
Style/GlobalStdStream:
118+
Enabled: false
119+
Style/HashAsLastArrayItem:
120+
Enabled: false
121+
Style/HashLikeCase:
122+
Enabled: false
123+
Style/OptionalBooleanParameter:
124+
Enabled: false
125+
Style/RedundantAssignment:
126+
Enabled: false
127+
Style/RedundantFetchBlock:
128+
Enabled: false
129+
Style/RedundantFileExtensionInRequire:
130+
Enabled: false
131+
Style/RedundantRegexpCharacterClass:
132+
Enabled: false
133+
Style/RedundantRegexpEscape:
134+
Enabled: false
135+
Style/SingleArgumentDig:
136+
Enabled: false
137+
Style/SlicingWithRange:
138+
Enabled: false
139+
Style/StringConcatenation:
140+
Enabled: false
141+
Performance/AncestorsInclude:
142+
Enabled: false
143+
Performance/BigDecimalWithNumericArgument:
144+
Enabled: false
145+
Performance/RedundantSortBlock:
146+
Enabled: false
147+
Performance/RedundantStringChars:
148+
Enabled: false
149+
Performance/ReverseFirst:
150+
Enabled: false
151+
Performance/SortReverse:
152+
Enabled: false
153+
Performance/Squeeze:
154+
Enabled: false
155+
Performance/StringInclude:
156+
Enabled: false

.rubocop_todo.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
# Offense count: 12
1010
# Configuration parameters: IgnoredMethods.
1111
Metrics/AbcSize:
12-
Max: 50
12+
Max: 60
1313

1414
# Offense count: 2
1515
# Configuration parameters: CountComments, ExcludedMethods.
@@ -20,12 +20,12 @@ Metrics/BlockLength:
2020
# Offense count: 1
2121
# Configuration parameters: CountComments.
2222
Metrics/ClassLength:
23-
Max: 309
23+
Max: 400
2424

2525
# Offense count: 6
2626
# Configuration parameters: IgnoredMethods.
2727
Metrics/CyclomaticComplexity:
28-
Max: 17
28+
Max: 20
2929

3030
# Offense count: 15
3131
# Configuration parameters: CountComments, ExcludedMethods.
@@ -35,7 +35,7 @@ Metrics/MethodLength:
3535
# Offense count: 1
3636
# Configuration parameters: CountComments.
3737
Metrics/ModuleLength:
38-
Max: 123
38+
Max: 150
3939

4040
# Offense count: 3
4141
# Configuration parameters: CountKeywordArgs.
@@ -45,4 +45,4 @@ Metrics/ParameterLists:
4545
# Offense count: 6
4646
# Configuration parameters: IgnoredMethods.
4747
Metrics/PerceivedComplexity:
48-
Max: 17
48+
Max: 20

.travis.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
1+
dist: focal
12
language: ruby
23
cache: bundler
34
addons:
4-
chrome: stable
5+
apt:
6+
update: true
7+
packages:
8+
- libvips
9+
- libvips-dev
10+
- libvips-tools
11+
12+
before_install:
13+
- vips --version
14+
515
rvm:
616
- ruby-2.7
717
- ruby-2.6

Dockerfile

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
ARG RUBY_VERSION=2.7
2+
3+
FROM cimg/ruby:${RUBY_VERSION}
4+
5+
RUN \
6+
7+
# Install dependencies
8+
sudo apt-get update && \
9+
DEBIAN_FRONTEND=noninteractive sudo apt-get install -y \
10+
automake \
11+
build-essential \
12+
curl \
13+
fftw3-dev \
14+
gettext \
15+
gobject-introspection \
16+
gtk-doc-tools \
17+
libexif-dev \
18+
libfftw3-dev \
19+
libgif-dev \
20+
libglib2.0-dev \
21+
libgsf-1-dev \
22+
libgtk2.0-dev \
23+
libmagickwand-dev \
24+
libmatio-dev \
25+
libopenexr-dev \
26+
libopenslide-dev \
27+
liborc-0.4-dev \
28+
libpango1.0-dev \
29+
libpoppler-glib-dev \
30+
librsvg2-dev \
31+
libtiff5-dev \
32+
libwebp-dev \
33+
libxml2-dev \
34+
swig
35+
36+
37+
WORKDIR /app
38+
ADD . /app/
39+
40+
RUN \
41+
bundle install && \
42+
sudo /app/bin/install-vips
43+
44+
RUN \
45+
# Clean up
46+
sudo apt-get remove -y curl automake build-essential && \
47+
sudo apt-get autoremove -y && \
48+
sudo apt-get autoclean && \
49+
sudo apt-get clean && \
50+
sudo rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
51+

README.md

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ Or install it yourself as:
2727

2828
$ gem install capybara-screenshot-diff
2929

30+
### Requirements
31+
32+
* [for :vips driver] libvips 8.9 or later, see the [libvips install instructions](https://libvips.github.io/libvips/install.html)
33+
3034
## Usage
3135

3236
### Minitest
@@ -452,18 +456,70 @@ If you need to ignore multiple areas, you can supply an array of arrays:
452456
screenshot 'index', skip_area: [[0, 0, 64, 48], [17, 6, 27, 16]]
453457
```
454458

459+
### Enable VIPS image processing
460+
461+
By default for image processing is using ChunkyPNG, but there is option to switch to [Vips](https://www.rubydoc.info/gems/ruby-vips/Vips/Image)
462+
To switch to the Vips processor, you have 2 options:
463+
464+
* Globally: `Capybara::Screenshot::Diff.driver = :vips`
465+
* Per screenshot option: `screenshot 'index', driver: :vips`
466+
467+
With enabled VIPS there are new alternatives to process differences, which easier to find and support.
468+
For example, `shift_distance_limit` is very heavy operation, and instead better to use `median_filter_window_size`.
469+
470+
#### Tolerance level (vips only)
471+
472+
You can set a “tolerance” anywhere from 0% to 100%. This is the amount of change that's allowable.
473+
If the screenshot has changed by more than that amount, it'll flag it as a failure.
474+
475+
This is alternative to "Allowed difference size", only the difference that area calculates including valid pixels.
476+
But "tolerance" compares only different pixels.
477+
478+
You can use the `tolerance` option to the `screenshot` method to set level:
479+
480+
```ruby
481+
test 'unstable area' do
482+
visit '/'
483+
screenshot 'index', tolerance: 0.3
484+
end
485+
```
486+
487+
You can also set this globally:
488+
489+
```ruby
490+
Capybara::Screenshot::Diff.tolerance = 0.3
491+
```
492+
493+
#### Median filter size (vips only)
494+
495+
This is an alternative to "Allowed shift distance", but much faster.
496+
You can find more about this strategy on [Median Filter](https://en.wikipedia.org/wiki/Median_filter).
497+
Think about this like smoothing of the image, before comparison.
498+
499+
You can use the `median_filter_window_size` option to the `screenshot` method to set level:
500+
501+
```ruby
502+
test 'unstable area' do
503+
visit '/'
504+
screenshot 'index', median_filter_window_size: 2
505+
end
506+
```
455507

456508
## Development
457509

458-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
510+
After checking out the repo, run `bin/setup` to install dependencies.
511+
Then, run `rake test` to run the tests.
512+
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
459513

460514
To install this gem onto your local machine, run `bundle exec rake install`.
461515

462516
To release a new version, update the version number in `lib/capybara/screenshot/diff/version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
463517

464518
## Contributing
465519

466-
Bug reports and pull requests are welcome on GitHub at https://github.com/donv/capybara-screenshot-diff. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
520+
Bug reports and pull requests are welcome on GitHub at https://github.com/donv/capybara-screenshot-diff.
521+
This project is intended to be a safe, welcoming space for collaboration,
522+
and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
467523

468524

469525
## License

bin/install-vips

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
version=${VIPS_VERSION:-8.10.0}
6+
7+
wget "https://github.com/libvips/libvips/releases/download/v$version/vips-$version.tar.gz"
8+
tar xf "vips-$version.tar.gz"
9+
cd "vips-$version"
10+
CXXFLAGS=-D_GLIBCXX_USE_CXX11_ABI=0 ./configure --enable-debug=no --without-python "$*"
11+
make && make install && ldconfig

gems.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,8 @@
44

55
# Specify your gem's dependencies in capybara-screenshot-diff.gemspec
66
gemspec path: __dir__
7+
8+
gem 'oily_png', platform: :ruby
9+
10+
gem 'image_processing', require: false
11+
gem 'ruby-vips', require: false

lib/capybara/screenshot/diff.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ module Diff
4545
mattr_accessor(:enabled) { true }
4646
mattr_accessor :shift_distance_limit
4747
mattr_accessor :skip_area
48+
mattr_accessor(:driver) { :chunky_png }
49+
mattr_accessor(:tolerance) { 0.001 }
4850

4951
def self.included(clas)
5052
clas.include TestMethods

0 commit comments

Comments
 (0)