lib/capybara/screenshot/diff/image_compare.rb in capybara-screenshot-diff-0.11.3 vs lib/capybara/screenshot/diff/image_compare.rb in capybara-screenshot-diff-0.12.0
- old
+ new
@@ -6,12 +6,11 @@
# Compare two images and determine if they are equal, different, or within som comparison
# range considering color values and difference area size.
class ImageCompare
include ChunkyPNG::Color
- attr_reader :annotated_new_file_name, :annotated_old_file_name, :new_file_name,
- :old_file_name
+ attr_reader :annotated_new_file_name, :annotated_old_file_name, :new_file_name, :old_file_name
def initialize(new_file_name, old_file_name = nil, dimensions: nil, color_distance_limit: nil,
area_size_limit: nil, shift_distance_limit: nil)
@new_file_name = new_file_name
@color_distance_limit = color_distance_limit
@@ -132,22 +131,38 @@
private
def calculate_metrics
old_file, new_file = load_image_files(@old_file_name, @new_file_name)
- @max_color_distance = 0 if old_file == new_file
+ if old_file == new_file
+ @max_color_distance = 0
+ @max_shift_distance = 0
+ return
+ end
old_image, new_image = load_images(old_file, new_file)
+ calculate_max_color_distance(new_image, old_image)
+ calculate_max_shift_limit(new_image, old_image)
+ end
+ def calculate_max_color_distance(new_image, old_image)
pixel_pairs = old_image.pixels.zip(new_image.pixels)
@max_color_distance = pixel_pairs.inject(0) do |max, (p1, p2)|
d = ChunkyPNG::Color.euclidean_distance_rgba(p1, p2)
[max, d].max
end
+ end
- (0...new_image.width).each do |_x|
- (0...new_image.height).each do |y|
+ def calculate_max_shift_limit(new_img, old_img)
+ (0...new_img.width).each do |x|
+ (0...new_img.height).each do |y|
+ shift_distance =
+ shift_distance_at(new_img, old_img, x, y, color_distance_limit: @color_distance_limit)
+ if shift_distance && (@max_shift_distance.nil? || shift_distance > @max_shift_distance)
+ @max_shift_distance = shift_distance
+ return if @max_shift_distance == Float::INFINITY # rubocop: disable Lint/NonLocalExitFromIterator
+ end
end
end
end
def not_different
@@ -257,13 +272,17 @@
if !@max_color_distance || color_distance > @max_color_distance
@max_color_distance = color_distance
end
color_matches = color_distance == 0 || (@color_distance_limit && @color_distance_limit > 0 &&
color_distance <= @color_distance_limit)
- return color_matches unless @shift_distance_limit
+ return color_matches if !@shift_distance_limit || @max_shift_distance == Float::INFINITY
shift_distance =
- shift_distance_at(new_img, old_img, x, y, color_distance_limit: @color_distance_limit)
+ if color_matches
+ 0
+ else
+ shift_distance_at(new_img, old_img, x, y, color_distance_limit: @color_distance_limit)
+ end
if shift_distance && (@max_shift_distance.nil? || shift_distance > @max_shift_distance)
@max_shift_distance = shift_distance
end
color_matches
end
@@ -291,22 +310,23 @@
def shift_distance_at(new_img, old_img, x, y, color_distance_limit:)
org_color = old_img[x, y]
shift_distance = 0
loop do
bounds_breached = 0
- if (y - shift_distance) >= 0 # top
+ top_row = y - shift_distance
+ if top_row >= 0 # top
([0, x - shift_distance].max..[x + shift_distance, new_img.width - 1].min).each do |dx|
- if color_matches(new_img, org_color, dx, y - shift_distance, color_distance_limit)
+ if color_matches(new_img, org_color, dx, top_row, color_distance_limit)
return shift_distance
end
end
else
bounds_breached += 1
end
if shift_distance > 0
if (x - shift_distance) >= 0 # left
- ([0, y - shift_distance + 1].max..[y + shift_distance, new_img.height - 2].min)
+ ([0, top_row + 1].max..[y + shift_distance, new_img.height - 2].min)
.each do |dy|
if color_matches(new_img, org_color, x - shift_distance, dy, color_distance_limit)
return shift_distance
end
end
@@ -321,11 +341,11 @@
end
else
bounds_breached += 1
end
if (x + shift_distance) < new_img.width # right
- ([0, y - shift_distance + 1].max..[y + shift_distance, new_img.height - 2].min)
+ ([0, top_row + 1].max..[y + shift_distance, new_img.height - 2].min)
.each do |dy|
if color_matches(new_img, org_color, x + shift_distance, dy, color_distance_limit)
return shift_distance
end
end
@@ -334,10 +354,10 @@
end
end
break if bounds_breached == 4
shift_distance += 1
end
- nil
+ Float::INFINITY
end
def color_matches(new_img, org_color, dx, dy, color_distance_limit)
new_color = new_img[dx, dy]
return new_color == org_color unless color_distance_limit