image_compare 1.0.0.pre.dev

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a67b91873ee2ca3ec939803ef3ff7c7e116ce75e48d4643340aae67f48c59225
4
+ data.tar.gz: 2795771468140989921e1ec9afffa2f9616f5363df7106e050ebcb36871659b0
5
+ SHA512:
6
+ metadata.gz: 39a0d7d0bc330345bc4a9624bbbd721f7206db5d5c0d5900bfaa78bb0eec90dd9c03598d683c7f165a78549a8d311edaa7e206b5773abe96672479b25a322851
7
+ data.tar.gz: 3fc93372828b8354867e63ac3e80cd2998fdd025ef9e3601a239d952f7ec0bfbdff3cd148bd03c4feb1a2c9cddf0be73c39da65ad55276639f3ac392886af1fa
data/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # Change log
2
+
3
+ ## main
4
+ - Add Color mode to generate "normal" diff images ([@gsguma][], [@cristianofmc][])
5
+
6
+ [@gsguma]: https://github.com/gsguma
7
+ [@cristianofmc]: https://github.com/cristianofmc
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 instantink
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 all
13
+ 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 THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,119 @@
1
+ [![Gem Version](https://badge.fury.io/rb/image_compare.svg)](https://rubygems.org/gems/image_compare)
2
+ [![Build](https://github.com/instantink/image_compare/workflows/Build/badge.svg)](https://github.com/instantink/image_compare/actions)
3
+
4
+ # ImageCompare
5
+
6
+ Compare PNG images in pure Ruby (uses [ChunkyPNG](https://github.com/wvanbergen/chunky_png)) using different algorithms.
7
+ This is an utility library for image regression testing.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'image_compare'
15
+ ```
16
+
17
+ Or adding to your project:
18
+
19
+ ```ruby
20
+ # my-cool-gem.gemspec
21
+ Gem::Specification.new do |spec|
22
+ # ...
23
+ spec.add_dependency 'image_compare'
24
+ # ...
25
+ end
26
+ ```
27
+
28
+ 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.
29
+
30
+ ## Modes
31
+
32
+ ImageCompare supports different ways (_modes_) of comparing images.
33
+
34
+ Source images used in examples:
35
+
36
+ <img src='https://raw.githubusercontent.com/instantink/image_compare/master/spec/fixtures/a.png' width='300' />
37
+ <img src='https://raw.githubusercontent.com/instantink/image_compare/master/spec/fixtures/b.png' width='300' />
38
+
39
+ ### Base (RGB) mode
40
+
41
+ Compare pixels by values, resulting score is a ratio of unequal pixels.
42
+ Resulting diff represents per-channel difference.
43
+
44
+ <img src='https://raw.githubusercontent.com/instantink/image_compare/master/spec/fixtures/rgb_diff.png' width='300' />
45
+
46
+ ### Grayscale mode
47
+
48
+ Compare pixels as grayscale (by brightness and alpha), resulting score is a ratio of unequal pixels (with respect to provided tolerance).
49
+
50
+ Resulting diff contains grayscale version of the first image with different pixels highlighted in red and red bounding box.
51
+
52
+ <img src='https://raw.githubusercontent.com/instantink/image_compare/master/spec/fixtures/grayscale_diff.png' width='300' />
53
+
54
+ ### Delta
55
+
56
+ Compare pixels using [Delta E](https://en.wikipedia.org/wiki/Color_difference) distance.
57
+ Resulting diff contains grayscale version of the first image with different pixels highlighted in red (with respect to diff score).
58
+
59
+ <img src='https://raw.githubusercontent.com/instantink/image_compare/master/spec/fixtures/delta_diff.png' width='300' />
60
+
61
+ ## Usage
62
+
63
+ ```ruby
64
+ # create new matcher with default threshold equals to 0
65
+ # and base (RGB) mode
66
+ cmp = ImageCompare::Matcher.new
67
+ cmp.mode #=> ImageCompare::Modes::RGB
68
+
69
+ # create matcher with specific threshold
70
+ cmp = ImageCompare::Matcher.new threshold: 0.05
71
+ cmp.threshold #=> 0.05
72
+
73
+ # or with a lower threshold (in case you want to test that there is some difference)
74
+ cmp = ImageCompare::Matcher.new lower_threshold: 0.01
75
+ cmp.lower_threshold #=> 0.01
76
+
77
+ # create zero-tolerance grayscale matcher
78
+ cmp = ImageCompare::Matcher.new mode: :grayscale, tolerance: 0
79
+ cmp.mode #=> ImageCompare::Modes::Grayscale
80
+
81
+ res = cmp.compare(path_1, path_2)
82
+ res #=> ImageCompare::Result
83
+ res.match? #=> true
84
+ res.score #=> 0.0
85
+
86
+ # Return diff image object
87
+ res.difference_image #=> ImageCompare::Image
88
+ res.difference_image.save(new_path)
89
+
90
+ # without explicit matcher
91
+ res = ImageCompare.compare(path_1, path_2, options)
92
+
93
+ # equals to
94
+ res = ImageCompare::Matcher.new(options).compare(path_1, path_2)
95
+ ```
96
+
97
+ ## Excluding rectangle
98
+
99
+ <img src='https://raw.githubusercontent.com/instantink/image_compare/master/spec/fixtures/a.png' width='300' />
100
+ <img src='https://raw.githubusercontent.com/instantink/image_compare/master/spec/fixtures/a1.png' width='300' />
101
+
102
+ You can exclude rectangle from comparing by passing `:exclude_rect` to `compare`.
103
+ E.g., if `path_1` and `path_2` contain images above
104
+ ```ruby
105
+ ImageCompare.compare(path_1, path_2, exclude_rect: [200, 150, 275, 200]).match? # => true
106
+ ```
107
+ `[200, 150, 275, 200]` is array of two vertices of rectangle -- (200, 150) is left-top vertex and (275, 200) is right-bottom.
108
+
109
+ ## Including rectangle
110
+
111
+ You can set bounds of comparing by passing `:include_rect` to `compare` with array similar to previous example
112
+
113
+ ## Contributing
114
+
115
+ Bug reports and pull requests are welcome on GitHub at https://github.com/instantink/image_compare.
116
+
117
+ ## License
118
+
119
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/bin/console ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'image_compare'
5
+ require 'pry'
6
+
7
+ Pry.start
data/bin/setup ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'chunky_png'
4
+
5
+ begin
6
+ require 'oily_png' unless RUBY_PLATFORM == 'java'
7
+ rescue LoadError => _e
8
+ nil
9
+ end
10
+
11
+ module ImageCompare
12
+ module ColorMethods
13
+ include ChunkyPNG::Color
14
+
15
+ def brightness(a)
16
+ 0.3 * r(a) + 0.59 * g(a) + 0.11 * b(a)
17
+ end
18
+
19
+ def red
20
+ rgb(255, 0, 0)
21
+ end
22
+
23
+ def green
24
+ rgb(0, 255, 0)
25
+ end
26
+
27
+ def blue
28
+ rgb(0, 0, 255)
29
+ end
30
+
31
+ def yellow
32
+ rgb(255, 255, 51)
33
+ end
34
+
35
+ def orange
36
+ rgb(255, 128, 0)
37
+ end
38
+
39
+ def transparent
40
+ rgba(255, 255, 255, 255)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'image_compare/color_methods'
4
+
5
+ module ImageCompare
6
+ class Image < ChunkyPNG::Image
7
+ include ColorMethods
8
+
9
+ def each_pixel
10
+ height.times do |y|
11
+ current_row = row(y) || []
12
+ current_row.each_with_index do |pixel, x|
13
+ yield(pixel, x, y)
14
+ end
15
+ end
16
+ end
17
+
18
+ def compare_each_pixel(image, area: nil)
19
+ area = bounding_rect if area.nil?
20
+ (area.top..area.bot).each do |y|
21
+ current_row = row(y) || []
22
+ range = (area.left..area.right)
23
+ next if image.row(y).slice(range) == current_row.slice(range)
24
+ (area.left..area.right).each do |x|
25
+ yield(self[x, y], image[x, y], x, y)
26
+ end
27
+ end
28
+ end
29
+
30
+ def to_grayscale
31
+ each_pixel do |pixel, x, y|
32
+ self[x, y] = grayscale(brightness(pixel).round)
33
+ end
34
+ self
35
+ end
36
+
37
+ def with_alpha(value)
38
+ each_pixel do |pixel, x, y|
39
+ self[x, y] = rgba(r(pixel), g(pixel), b(pixel), value)
40
+ end
41
+ self
42
+ end
43
+
44
+ def sizes_match?(image)
45
+ [width, height] == [image.width, image.height]
46
+ end
47
+
48
+ def inspect
49
+ "Image:#{object_id}<#{width}x#{height}>"
50
+ end
51
+
52
+ def highlight_rectangle(rect, color = :red)
53
+ raise ArgumentError, "Undefined color: #{color}" unless respond_to?(color)
54
+ return self if rect.nil?
55
+ rect(*rect.bounds, send(color))
56
+ self
57
+ end
58
+
59
+ def bounding_rect
60
+ Rectangle.new(0, 0, width - 1, height - 1)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImageCompare
4
+ class Matcher
5
+ require 'image_compare/image'
6
+ require 'image_compare/result'
7
+ require 'image_compare/modes'
8
+
9
+ MODES = {
10
+ rgb: 'RGB',
11
+ delta: 'Delta',
12
+ grayscale: 'Grayscale',
13
+ color: 'Color'
14
+ }.freeze
15
+
16
+ attr_reader :mode
17
+
18
+ def initialize(**options)
19
+ mode_type = options.delete(:mode) || :rgb
20
+ raise ArgumentError, "Undefined mode: #{mode_type}" unless MODES.key?(mode_type)
21
+ @mode = Modes.const_get(MODES[mode_type]).new(**options)
22
+ end
23
+
24
+ def compare(a, b)
25
+ a = Image.from_file(a) unless a.is_a?(Image)
26
+ b = Image.from_file(b) unless b.is_a?(Image)
27
+
28
+ unless a.sizes_match?(b)
29
+ raise SizesMismatchError,
30
+ "Size mismatch: first image size: #{a.width}x#{a.height}, second image size: #{b.width}x#{b.height}"
31
+ end
32
+
33
+ image_area = Rectangle.new(0, 0, a.width - 1, a.height - 1)
34
+
35
+ unless mode.exclude_rect.nil?
36
+ unless image_area.contains?(mode.exclude_rect)
37
+ raise ArgumentError, 'Bounds must be in image'
38
+ end
39
+ end
40
+
41
+ unless mode.include_rect.nil?
42
+ unless image_area.contains?(mode.include_rect)
43
+ raise ArgumentError, 'Bounds must be in image'
44
+ end
45
+ unless mode.exclude_rect.nil?
46
+ unless mode.include_rect.contains?(mode.exclude_rect)
47
+ raise ArgumentError, 'Included area must contain excluded'
48
+ end
49
+ end
50
+ end
51
+
52
+ mode.compare(a, b)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImageCompare
4
+ module Modes
5
+ class Base
6
+ require 'image_compare/rectangle'
7
+ include ColorMethods
8
+
9
+ attr_reader :result, :threshold, :lower_threshold, :bounds, :exclude_rect, :include_rect
10
+
11
+ def initialize(threshold: 0.0, lower_threshold: 0.0, exclude_rect: nil, include_rect: nil)
12
+ @include_rect = Rectangle.new(*include_rect) unless include_rect.nil?
13
+ @exclude_rect = Rectangle.new(*exclude_rect) unless exclude_rect.nil?
14
+ @threshold = threshold
15
+ @lower_threshold = lower_threshold
16
+ @result = Result.new(self, threshold: threshold, lower_threshold: lower_threshold)
17
+ end
18
+
19
+ def compare(a, b)
20
+ result.image = a
21
+ @include_rect ||= a.bounding_rect
22
+ @bounds = Rectangle.new(*include_rect.bounds)
23
+
24
+ b.compare_each_pixel(a, area: include_rect) do |b_pixel, a_pixel, x, y|
25
+ next if pixels_equal?(b_pixel, a_pixel)
26
+ next if !exclude_rect.nil? && exclude_rect.contains_point?(x, y)
27
+ update_result(b_pixel, a_pixel, x, y)
28
+ end
29
+
30
+ result.score = score
31
+ result
32
+ end
33
+
34
+ def diff(bg, diff)
35
+ diff_image = background(bg).highlight_rectangle(exclude_rect, :blue)
36
+ diff.each do |pixels_pair|
37
+ pixels_diff(diff_image, *pixels_pair)
38
+ end
39
+ create_diff_image(bg, diff_image)
40
+ .highlight_rectangle(bounds)
41
+ .highlight_rectangle(include_rect, :green)
42
+ end
43
+
44
+ def score
45
+ result.diff.length.to_f / area
46
+ end
47
+
48
+ def update_result(*_args, x, y)
49
+ update_bounds(x, y)
50
+ end
51
+
52
+ def update_bounds(x, y)
53
+ bounds.left = [x, bounds.left].max
54
+ bounds.top = [y, bounds.top].max
55
+ bounds.right = [x, bounds.right].min
56
+ bounds.bot = [y, bounds.bot].min
57
+ end
58
+
59
+ def area
60
+ area = include_rect.area
61
+ return area if exclude_rect.nil?
62
+ area - exclude_rect.area
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImageCompare
4
+ module Modes
5
+ require 'image_compare/modes/base'
6
+
7
+ class Color < Base
8
+ include ColorMethods
9
+
10
+ DEFAULT_TOLERANCE = 16
11
+
12
+ attr_reader :tolerance
13
+
14
+ def initialize(**options)
15
+ @tolerance = options.delete(:tolerance) || DEFAULT_TOLERANCE
16
+ super(**options)
17
+ end
18
+
19
+ def diff(bg, diff)
20
+ diff_image = bg.highlight_rectangle(exclude_rect, :blue)
21
+
22
+ if area_in_exclude_rect?
23
+ diff_image
24
+ else
25
+ diff_image.highlight_rectangle(bounds)
26
+ end
27
+ end
28
+
29
+ def area_in_exclude_rect?
30
+ return false if exclude_rect.nil?
31
+
32
+ diff_area = {
33
+ left: bounds.bounds[0],
34
+ top: bounds.bounds[1],
35
+ right: bounds.bounds[2],
36
+ bot: bounds.bounds[3]
37
+ }
38
+
39
+ exclude_area = {
40
+ left: exclude_rect.bounds[0],
41
+ top: exclude_rect.bounds[1],
42
+ right: exclude_rect.bounds[2],
43
+ bot: exclude_rect.bounds[3]
44
+ }
45
+
46
+ diff_area[:left] <= exclude_area[:left] &&
47
+ diff_area[:top] <= exclude_area[:top] &&
48
+ diff_area[:right] >= exclude_area[:right] &&
49
+ diff_area[:bot] >= exclude_area[:bot]
50
+ end
51
+
52
+ def pixels_equal?(a, b)
53
+ alpha = color_similar?(a(a), a(b))
54
+ brightness = color_similar?(brightness(a), brightness(b))
55
+ brightness && alpha
56
+ end
57
+
58
+ def update_result(a, b, x, y)
59
+ super
60
+ @result.diff << [a, b, x, y]
61
+ end
62
+
63
+ def color_similar?(a, b)
64
+ d = (a - b).abs
65
+ d <= tolerance
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImageCompare
4
+ module Modes
5
+ require 'image_compare/modes/base'
6
+
7
+ class Delta < Base
8
+ attr_reader :tolerance
9
+
10
+ def initialize(**options)
11
+ @tolerance = options.delete(:tolerance) || 0.01
12
+ @delta_score = 0.0
13
+ super(**options)
14
+ end
15
+
16
+ private
17
+
18
+ def pixels_equal?(a, b)
19
+ a == b
20
+ end
21
+
22
+ def update_result(a, b, x, y)
23
+ d = euclid(a, b) / (MAX * Math.sqrt(3))
24
+ return if d <= tolerance
25
+ @result.diff << [a, b, x, y, d]
26
+ @delta_score += d
27
+ super
28
+ end
29
+
30
+ def background(bg)
31
+ Image.new(bg.width, bg.height, WHITE).with_alpha(0)
32
+ end
33
+
34
+ def euclid(a, b)
35
+ Math.sqrt(
36
+ (r(a) - r(b))**2 +
37
+ (g(a) - g(b))**2 +
38
+ (b(a) - b(b))**2
39
+ )
40
+ end
41
+
42
+ def create_diff_image(bg, diff_image)
43
+ bg.to_grayscale.compose!(diff_image, 0, 0)
44
+ end
45
+
46
+ def pixels_diff(d, *_args, x, y, a)
47
+ d[x, y] = rgba(MAX, 0, 0, (a * MAX).round)
48
+ end
49
+
50
+ def score
51
+ @delta_score / area
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImageCompare
4
+ module Modes
5
+ require 'image_compare/modes/base'
6
+
7
+ class Grayscale < Base
8
+ DEFAULT_TOLERANCE = 16
9
+
10
+ attr_reader :tolerance
11
+
12
+ def initialize(**options)
13
+ @tolerance = options.delete(:tolerance) || DEFAULT_TOLERANCE
14
+ super(**options)
15
+ end
16
+
17
+ def pixels_equal?(a, b)
18
+ alpha = color_similar?(a(a), a(b))
19
+ brightness = color_similar?(brightness(a), brightness(b))
20
+ brightness && alpha
21
+ end
22
+
23
+ def update_result(a, b, x, y)
24
+ super
25
+ @result.diff << [a, b, x, y]
26
+ end
27
+
28
+ def background(bg)
29
+ bg.to_grayscale
30
+ end
31
+
32
+ def pixels_diff(d, _a, _b, x, y)
33
+ d[x, y] = rgb(255, 0, 0)
34
+ end
35
+
36
+ def create_diff_image(_bg, diff_image)
37
+ diff_image
38
+ end
39
+
40
+ def color_similar?(a, b)
41
+ d = (a - b).abs
42
+ d <= tolerance
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImageCompare
4
+ module Modes
5
+ require 'image_compare/modes/base'
6
+
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,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImageCompare
4
+ module Modes
5
+ require 'image_compare/modes/rgb'
6
+ require 'image_compare/modes/grayscale'
7
+ require 'image_compare/modes/delta'
8
+ require 'image_compare/modes/color'
9
+ end
10
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImageCompare
4
+ class Rectangle
5
+ attr_accessor :left, :top, :right, :bot
6
+
7
+ def initialize(l, t, r, b)
8
+ @left = l
9
+ @top = t
10
+ @right = r
11
+ @bot = b
12
+ end
13
+
14
+ def area
15
+ (right - left + 1) * (bot - top + 1)
16
+ end
17
+
18
+ def contains?(rect)
19
+ (left <= rect.left) &&
20
+ (right >= rect.right) &&
21
+ (top <= rect.top) &&
22
+ (bot >= rect.bot)
23
+ end
24
+
25
+ def bounds
26
+ [left, top, right, bot]
27
+ end
28
+
29
+ def contains_point?(x, y)
30
+ x.between?(left, right) && y.between?(top, bot)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImageCompare
4
+ class Result
5
+ attr_accessor :score, :image
6
+ attr_reader :diff, :mode, :threshold, :lower_threshold
7
+
8
+ def initialize(mode, threshold:, lower_threshold:)
9
+ @score = 0.0
10
+ @diff = []
11
+ @threshold = threshold
12
+ @lower_threshold = lower_threshold
13
+ @mode = mode
14
+ end
15
+
16
+ def difference_image
17
+ @diff_image ||= mode.diff(image, diff)
18
+ end
19
+
20
+ def match?
21
+ score <= threshold && score >= lower_threshold
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImageCompare
4
+ VERSION = '1.0.0-dev'
5
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'image_compare/version'
4
+
5
+ module ImageCompare
6
+ class SizesMismatchError < StandardError
7
+ end
8
+
9
+ require 'image_compare/matcher'
10
+ require 'image_compare/color_methods'
11
+
12
+ def self.compare(path_a, path_b, **options)
13
+ Matcher.new(**options).compare(path_a, path_b)
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: image_compare
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0.pre.dev
5
+ platform: ruby
6
+ authors:
7
+ - cristianofmc
8
+ - gsguma
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2023-03-24 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: chunky_png
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '13.0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '13.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '3.9'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '3.9'
56
+ description: Image comparison lib built on top of ChunkyPNG
57
+ email:
58
+ - cristiano.fmc@hotmail.com
59
+ - giltonguma@gmail.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - CHANGELOG.md
65
+ - LICENSE.txt
66
+ - README.md
67
+ - bin/console
68
+ - bin/setup
69
+ - lib/image_compare.rb
70
+ - lib/image_compare/color_methods.rb
71
+ - lib/image_compare/image.rb
72
+ - lib/image_compare/matcher.rb
73
+ - lib/image_compare/modes.rb
74
+ - lib/image_compare/modes/base.rb
75
+ - lib/image_compare/modes/color.rb
76
+ - lib/image_compare/modes/delta.rb
77
+ - lib/image_compare/modes/grayscale.rb
78
+ - lib/image_compare/modes/rgb.rb
79
+ - lib/image_compare/rectangle.rb
80
+ - lib/image_compare/result.rb
81
+ - lib/image_compare/version.rb
82
+ homepage: https://github.com/instantink/image_compare
83
+ licenses:
84
+ - MIT
85
+ metadata:
86
+ bug_tracker_uri: https://github.com/instantink/image_compare/issues
87
+ changelog_uri: https://github.com/instantink/image_compare/blob/master/CHANGELOG.md
88
+ documentation_uri: https://github.com/instantink/image_compare
89
+ homepage_uri: https://github.com/instantink/image_compare
90
+ source_code_uri: https://github.com/instantink/image_compare
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: 3.2.0
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">"
103
+ - !ruby/object:Gem::Version
104
+ version: 1.3.1
105
+ requirements: []
106
+ rubygems_version: 3.4.1
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: Image comparison lib
110
+ test_files: []