pxdoppelganger 0.1.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 +11 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +37 -0
- data/README.md +49 -0
- data/bin/pxdoppelganger +5 -0
- data/lib/controller/analyzer.rb +76 -0
- data/lib/pxdoppelganger.rb +26 -0
- data/lib/pxdoppelganger/version.rb +13 -0
- data/pxdoppelganger.gemspec +16 -0
- data/tests/images/ottologo.png +0 -0
- data/tests/images/ottologo2.png +0 -0
- data/tests/images/ottologosmall.png +0 -0
- data/tests/rspec/analyzer_spec.rb +74 -0
- data/tests/rspec/pxdoppelganger_spec.rb +58 -0
- metadata +63 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c51c60a2ee727316dda9cc0fc8b4c73edb6c19f9
|
4
|
+
data.tar.gz: 3d623cc945a162ebe82470b83977eb1b6e9dc0e5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8b20cccc5c96cf628644bff2ce8e205ae1b64f5b77db311ab970e6d9175704475ed065f752ab225ebce6b0b9cd8ef698ad981b7da086bc5ba95068e64338d540
|
7
|
+
data.tar.gz: 839bf7efb354e0df470c6c9b303fb90cf3512edf9e7a3491c4cdaab01183f0894c1f9d567e0c3d59d9bc8e43ec1b9e285dbdef7836d7c6c2159b7a33dfb44fbc
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
pxdoppelganger (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
chunky_png (1.3.4)
|
10
|
+
diff-lcs (1.2.5)
|
11
|
+
oily_png (1.2.0)
|
12
|
+
chunky_png (~> 1.3.1)
|
13
|
+
rspec (3.3.0)
|
14
|
+
rspec-core (~> 3.3.0)
|
15
|
+
rspec-expectations (~> 3.3.0)
|
16
|
+
rspec-mocks (~> 3.3.0)
|
17
|
+
rspec-core (3.3.2)
|
18
|
+
rspec-support (~> 3.3.0)
|
19
|
+
rspec-expectations (3.3.1)
|
20
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
21
|
+
rspec-support (~> 3.3.0)
|
22
|
+
rspec-mocks (3.3.2)
|
23
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
24
|
+
rspec-support (~> 3.3.0)
|
25
|
+
rspec-support (3.3.0)
|
26
|
+
|
27
|
+
PLATFORMS
|
28
|
+
ruby
|
29
|
+
|
30
|
+
DEPENDENCIES
|
31
|
+
chunky_png
|
32
|
+
oily_png
|
33
|
+
pxdoppelganger!
|
34
|
+
rspec
|
35
|
+
|
36
|
+
BUNDLED WITH
|
37
|
+
1.10.5
|
data/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# pXdoppelganger
|
2
|
+
|
3
|
+
## what can it do for me?
|
4
|
+
|
5
|
+
* pXdoppelganger can compare two images for you.
|
6
|
+
* pXdoppelganger converts the images into bitstreams and thus analyze every pixcel.
|
7
|
+
* pXdoppelganger can tell you if those images are equal and what the percentual change is.
|
8
|
+
* pXdoppelganger can also show you the "difference" image between the two images.
|
9
|
+
|
10
|
+
## how do I use it?
|
11
|
+
|
12
|
+
install the gem:
|
13
|
+
```
|
14
|
+
gem install pxdoppelganger
|
15
|
+
```
|
16
|
+
and use it:
|
17
|
+
```
|
18
|
+
require 'pxdoppelganger'
|
19
|
+
```
|
20
|
+
|
21
|
+
provide paths to images:
|
22
|
+
```
|
23
|
+
images = PXDoppelganger::Images.new('~/Downloads/Image1.png', '~/Downloads/Image2.png')
|
24
|
+
```
|
25
|
+
|
26
|
+
see if images are equal:
|
27
|
+
```
|
28
|
+
images.equal?
|
29
|
+
=> true/false
|
30
|
+
```
|
31
|
+
|
32
|
+
get the difference of the two images (in percent):
|
33
|
+
```
|
34
|
+
images.difference
|
35
|
+
=> 1.3849177058385036
|
36
|
+
```
|
37
|
+
|
38
|
+
save the difference-image:
|
39
|
+
```
|
40
|
+
images.save_difference_image('~Documents/analysis/diff_image.png')
|
41
|
+
```
|
42
|
+
|
43
|
+
## how do I contribute?
|
44
|
+
|
45
|
+
open pull request
|
46
|
+
|
47
|
+
## license
|
48
|
+
|
49
|
+
MIT: http://opensource.org/licenses/MIT
|
data/bin/pxdoppelganger
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'oily_png'
|
2
|
+
require 'chunky_png'
|
3
|
+
require 'fileutils'
|
4
|
+
include OilyPNG::Color
|
5
|
+
include ChunkyPNG::Color
|
6
|
+
|
7
|
+
class Analyzer
|
8
|
+
|
9
|
+
attr_accessor :difference, :difference_in_percent
|
10
|
+
|
11
|
+
def initialize(base_image, new_image)
|
12
|
+
raise 'The images need to be in png format' unless are_images_png?(base_image, new_image)
|
13
|
+
self.images = [
|
14
|
+
ChunkyPNG::Image.from_file(base_image),
|
15
|
+
ChunkyPNG::Image.from_file(new_image),
|
16
|
+
]
|
17
|
+
raise_different_size unless images_have_same_width?
|
18
|
+
self.difference = difference_analyzer
|
19
|
+
self.difference_in_percent = percent_calculator(difference)
|
20
|
+
end
|
21
|
+
|
22
|
+
def save_output(path)
|
23
|
+
@output.save(path)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_accessor :images
|
29
|
+
|
30
|
+
def are_images_png?(base, new)
|
31
|
+
true if (base.downcase.include? 'png') && (new.downcase.include? 'png')
|
32
|
+
end
|
33
|
+
|
34
|
+
def images_have_same_width?
|
35
|
+
images.first.width == images.last.width
|
36
|
+
end
|
37
|
+
|
38
|
+
def raise_different_size
|
39
|
+
raise "The images do not have the same width."
|
40
|
+
end
|
41
|
+
|
42
|
+
def difference_analyzer
|
43
|
+
@output = ChunkyPNG::Image.new(images.first.width, images.first.height, WHITE)
|
44
|
+
difference = []
|
45
|
+
images.first.height.times do |y|
|
46
|
+
images.first.row(y).each_with_index do |pixel, x|
|
47
|
+
begin
|
48
|
+
unless pixel == images.last[x,y]
|
49
|
+
score = Math.sqrt(
|
50
|
+
(r(images.last[x,y]) - r(pixel)) ** 2 +
|
51
|
+
(g(images.last[x,y]) - g(pixel)) ** 2 +
|
52
|
+
(b(images.last[x,y]) - b(pixel)) ** 2
|
53
|
+
) / Math.sqrt(MAX ** 2 * 3)
|
54
|
+
|
55
|
+
@output[x,y] = grayscale(MAX - (score * MAX).round)
|
56
|
+
difference << score
|
57
|
+
end
|
58
|
+
rescue ChunkyPNG::OutOfBounds
|
59
|
+
# "out of bound error"
|
60
|
+
# in Y-Direction (= one image is longer than the other)
|
61
|
+
# if webpages change, they may have a different vertical length
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
difference
|
66
|
+
end
|
67
|
+
|
68
|
+
def percent_calculator(difference)
|
69
|
+
if difference == []
|
70
|
+
0
|
71
|
+
else
|
72
|
+
((difference.inject {|sum, value| sum + value} / images.first.pixels.length) * 100).to_f
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'controller/analyzer'
|
3
|
+
|
4
|
+
module PXDoppelganger
|
5
|
+
|
6
|
+
class Images
|
7
|
+
|
8
|
+
def initialize(base_image, new_image)
|
9
|
+
@result = Analyzer.new(base_image, new_image)
|
10
|
+
end
|
11
|
+
|
12
|
+
def equal?
|
13
|
+
@result.difference == []
|
14
|
+
end
|
15
|
+
|
16
|
+
def difference
|
17
|
+
@result.difference_in_percent
|
18
|
+
end
|
19
|
+
|
20
|
+
def save_difference_image(path)
|
21
|
+
@result.save_output(path)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.expand_path('../lib/pxdoppelganger/version', __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |gem|
|
4
|
+
gem.authors = %w(Finn Lorbeer)
|
5
|
+
gem.version = PXDoppelganger::Version
|
6
|
+
gem.name = 'pxdoppelganger'
|
7
|
+
gem.platform = Gem::Platform::RUBY
|
8
|
+
gem.require_paths = %w(lib)
|
9
|
+
gem.license = 'MIT'
|
10
|
+
gem.email = %w(finn.von.friesland@googlemail.com)
|
11
|
+
gem.summary = "pXdoppelganger will help you in your automated design regression testing"
|
12
|
+
gem.description = %q{pXdoppelganger compares two images and can tell you the exact difference (in % of pixels changed). If you compare two screenshots of you app before and after a release, it will help you to automate your design regression tests. It follows the suggestions of image comparison by in Jeff Kreeftmeijers blog: jeffkreeftmeijer.com/2011/comparing-images-and-creating-image-diffs/}
|
13
|
+
gem.homepage = 'https://www.otto.de'
|
14
|
+
gem.files = `git ls-files`.split($\)
|
15
|
+
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
16
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'fileutils'
|
3
|
+
require '../../lib/controller/analyzer'
|
4
|
+
|
5
|
+
describe '#analyzer' do
|
6
|
+
|
7
|
+
PATH_TO_OTTO_LOGO = '../images/ottologo.png'
|
8
|
+
PATH_TO_DIFFERENT_LOGO = '../images/ottologo2.png'
|
9
|
+
DIFFERENCE_IMAGE = '../images/otto_DIFF.png'
|
10
|
+
|
11
|
+
after(:each) { FileUtils.rm DIFFERENCE_IMAGE if File.exist? (DIFFERENCE_IMAGE) }
|
12
|
+
|
13
|
+
it "should throw an exception if the images is not png" do
|
14
|
+
expect {
|
15
|
+
Analyzer.new('some_wrong/path.JPG', 'another_wrong/path.JPG')
|
16
|
+
}.to raise_error("The images need to be in png format")
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should throw an exception if the image cannot be found" do
|
20
|
+
expect {
|
21
|
+
Analyzer.new('some_wrong/path.png', 'another_wrong/path.PNG')
|
22
|
+
}.to raise_error(Errno::ENOENT)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should throw an exception if the images do not have the same width" do
|
26
|
+
expect {
|
27
|
+
Analyzer.new(PATH_TO_OTTO_LOGO, '../images/ottologosmall.png')
|
28
|
+
}.to raise_error("The images do not have the same width.")
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should return an empty array if both analyzed images are the same" do
|
32
|
+
analyzer = Analyzer.new(PATH_TO_OTTO_LOGO, PATH_TO_OTTO_LOGO)
|
33
|
+
expect(
|
34
|
+
analyzer.difference.empty?
|
35
|
+
).to be(true)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should return 0% change if both analyzed images are the same" do
|
39
|
+
analyzer = Analyzer.new(PATH_TO_OTTO_LOGO, PATH_TO_OTTO_LOGO)
|
40
|
+
expect(
|
41
|
+
analyzer.difference_in_percent
|
42
|
+
).to eq(0)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should return a not empty array if both analyzed images are not the same" do
|
46
|
+
analyzer = Analyzer.new(PATH_TO_OTTO_LOGO, PATH_TO_DIFFERENT_LOGO)
|
47
|
+
expect(
|
48
|
+
analyzer.difference.empty?
|
49
|
+
).to be(false)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should return x% change if the analyzed images are not the same" do
|
53
|
+
analyzer = Analyzer.new(PATH_TO_OTTO_LOGO, PATH_TO_DIFFERENT_LOGO)
|
54
|
+
expect(
|
55
|
+
analyzer.difference_in_percent.round(2)
|
56
|
+
).to eq(1.38)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should create an output image" do
|
60
|
+
analyzer = Analyzer.new(PATH_TO_OTTO_LOGO, PATH_TO_DIFFERENT_LOGO)
|
61
|
+
expect(
|
62
|
+
analyzer.save_output(DIFFERENCE_IMAGE)
|
63
|
+
).to be_a(File)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should save an output image" do
|
67
|
+
analyzer = Analyzer.new(PATH_TO_OTTO_LOGO, PATH_TO_DIFFERENT_LOGO)
|
68
|
+
analyzer.save_output(DIFFERENCE_IMAGE)
|
69
|
+
expect(
|
70
|
+
File.exist? (DIFFERENCE_IMAGE)
|
71
|
+
).to be(true)
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require '../../lib/controller/analyzer'
|
3
|
+
require '../../lib/pxdoppelganger'
|
4
|
+
|
5
|
+
PATH_TO_OTTO_LOGO = '../images/ottologo.png'
|
6
|
+
PATH_TO_DIFFERENT_LOGO = '../images/ottologo2.png'
|
7
|
+
DIFFERENCE_IMAGE = '../images/otto_DIFF.png'
|
8
|
+
|
9
|
+
describe '#equal?' do
|
10
|
+
|
11
|
+
it 'returns "true" if two images are equal' do
|
12
|
+
pxdoppelganger = PXDoppelganger::Images.new(
|
13
|
+
PATH_TO_OTTO_LOGO, PATH_TO_OTTO_LOGO
|
14
|
+
)
|
15
|
+
expect(
|
16
|
+
pxdoppelganger.equal?
|
17
|
+
).to be(true)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'returns "false" if two images are equal' do
|
21
|
+
pxdoppelganger = PXDoppelganger::Images.new(
|
22
|
+
PATH_TO_OTTO_LOGO, PATH_TO_DIFFERENT_LOGO
|
23
|
+
)
|
24
|
+
expect(
|
25
|
+
pxdoppelganger.equal?
|
26
|
+
).to be(false)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#difference' do
|
32
|
+
|
33
|
+
it 'returns the %-difference of two images' do
|
34
|
+
pxdoppelganger = PXDoppelganger::Images.new(
|
35
|
+
PATH_TO_OTTO_LOGO, PATH_TO_DIFFERENT_LOGO
|
36
|
+
)
|
37
|
+
expect(
|
38
|
+
pxdoppelganger.difference.round(2)
|
39
|
+
).to eq(1.38)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#save_difference_image' do
|
45
|
+
|
46
|
+
after(:each) { FileUtils.rm DIFFERENCE_IMAGE if File.exist? (DIFFERENCE_IMAGE) }
|
47
|
+
|
48
|
+
it 'saves the difference image' do
|
49
|
+
pxdoppelganger = PXDoppelganger::Images.new(
|
50
|
+
PATH_TO_OTTO_LOGO, PATH_TO_DIFFERENT_LOGO
|
51
|
+
)
|
52
|
+
pxdoppelganger.save_difference_image(DIFFERENCE_IMAGE)
|
53
|
+
expect(
|
54
|
+
File.exist? (DIFFERENCE_IMAGE)
|
55
|
+
).to be(true)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pxdoppelganger
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Finn
|
8
|
+
- Lorbeer
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-07-21 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: 'pXdoppelganger compares two images and can tell you the exact difference
|
15
|
+
(in % of pixels changed). If you compare two screenshots of you app before and after
|
16
|
+
a release, it will help you to automate your design regression tests. It follows
|
17
|
+
the suggestions of image comparison by in Jeff Kreeftmeijers blog: jeffkreeftmeijer.com/2011/comparing-images-and-creating-image-diffs/'
|
18
|
+
email:
|
19
|
+
- finn.von.friesland@googlemail.com
|
20
|
+
executables:
|
21
|
+
- pxdoppelganger
|
22
|
+
extensions: []
|
23
|
+
extra_rdoc_files: []
|
24
|
+
files:
|
25
|
+
- ".gitignore"
|
26
|
+
- Gemfile
|
27
|
+
- Gemfile.lock
|
28
|
+
- README.md
|
29
|
+
- bin/pxdoppelganger
|
30
|
+
- lib/controller/analyzer.rb
|
31
|
+
- lib/pxdoppelganger.rb
|
32
|
+
- lib/pxdoppelganger/version.rb
|
33
|
+
- pxdoppelganger.gemspec
|
34
|
+
- tests/images/ottologo.png
|
35
|
+
- tests/images/ottologo2.png
|
36
|
+
- tests/images/ottologosmall.png
|
37
|
+
- tests/rspec/analyzer_spec.rb
|
38
|
+
- tests/rspec/pxdoppelganger_spec.rb
|
39
|
+
homepage: https://www.otto.de
|
40
|
+
licenses:
|
41
|
+
- MIT
|
42
|
+
metadata: {}
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
requirements: []
|
58
|
+
rubyforge_project:
|
59
|
+
rubygems_version: 2.4.8
|
60
|
+
signing_key:
|
61
|
+
specification_version: 4
|
62
|
+
summary: pXdoppelganger will help you in your automated design regression testing
|
63
|
+
test_files: []
|