class Capybara::Screenshot::Diff::Drivers::ChunkyPNGDriver::DifferenceRegionFinder
Attributes
Public Class Methods
Source
# File lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb, line 84 def initialize(comparison, driver = nil) @comparison = comparison @driver = driver @color_distance_limit = comparison.options[:color_distance_limit] @shift_distance_limit = comparison.options[:shift_distance_limit] @skip_area = comparison.options[:skip_area] end
Public Instance Methods
Source
# File lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb, line 218 def color_distance_at(new_img, old_img, x, y, shift_distance_limit:) org_color = old_img[x, y] if shift_distance_limit start_x = [0, x - shift_distance_limit].max end_x = [x + shift_distance_limit, new_img.width - 1].min xs = (start_x..end_x).to_a start_y = [0, y - shift_distance_limit].max end_y = [y + shift_distance_limit, new_img.height - 1].min ys = (start_y..end_y).to_a new_pixels = xs.product(ys) distances = new_pixels.map do |dx, dy| ChunkyPNG::Color.euclidean_distance_rgba(org_color, new_img[dx, dy]) end distances.min else ChunkyPNG::Color.euclidean_distance_rgba(org_color, new_img[x, y]) end end
Source
# File lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb, line 291 def color_matches(new_img, org_color, x, y, color_distance_limit) new_color = new_img[x, y] return new_color == org_color unless color_distance_limit color_distance = ChunkyPNG::Color.euclidean_distance_rgba(org_color, new_color) color_distance <= color_distance_limit end
Source
# File lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb, line 124 def difference_level(_diff_mask, base_image, region) image_area_size = @driver.image_area_size(base_image) return nil if image_area_size.zero? region.size.to_f / image_area_size end
Source
# File lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb, line 176 def find_bottom(old_img, new_img, left, right, bottom, cache:) if bottom (old_img.height - 1).step(bottom + 1, -1).find do |y| (left..right).find do |x| bottom = y unless same_color?(old_img, new_img, x, y, cache: cache) end end end bottom end
Source
# File lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb, line 131 def find_diff_rectangle(org_img, new_img, area_coordinates, cache:) left, top, right, bottom = find_left_right_and_top(org_img, new_img, area_coordinates, cache: cache) bottom = find_bottom(org_img, new_img, left, right, bottom, cache: cache) Region.from_edge_coordinates(left, top, right, bottom) end
Source
# File lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb, line 97 def find_difference_region(comparison) new_image, base_image, = comparison.new_image, comparison.base_image meta = {} meta[:max_color_distance] = 0 meta[:max_shift_distance] = 0 if shift_distance_limit region = find_top(base_image, new_image, cache: meta) region = if region.nil? || region[1].nil? nil else find_diff_rectangle(base_image, new_image, region, cache: meta) end result = Difference.new(region, meta, comparison) unless result.blank? meta[:max_color_distance] = meta[:max_color_distance].ceil(1) if meta[:max_color_distance] if comparison.options[:tolerance] meta[:difference_level] = difference_level(nil, base_image, region) end end result end
Source
# File lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb, line 147 def find_left_right_and_top(old_img, new_img, region, cache:) region = region.is_a?(Region) ? region.to_edge_coordinates : region left = region[0] || old_img.width - 1 top = region[1] right = region[2] || 0 bottom = region[3] old_img.height.times do |y| (0...left).find do |x| next if same_color?(old_img, new_img, x, y, cache: cache) top ||= y bottom = y left = x right = x if x > right x end (old_img.width - 1).step(right + 1, -1).find do |x| unless same_color?(old_img, new_img, x, y, cache: cache) bottom = y right = x end end end [left, top, right, bottom] end
Source
# File lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb, line 138 def find_top(old_img, new_img, cache:) old_img.height.times do |y| old_img.width.times do |x| return [x, y, x, y] unless same_color?(old_img, new_img, x, y, cache: cache) end end nil end
Source
# File lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb, line 93 def perform find_difference_region(@comparison) end
Source
# File lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb, line 188 def same_color?(old_img, new_img, x, y, cache:) return true if skipped_region?(x, y) color_distance = color_distance_at(new_img, old_img, x, y, shift_distance_limit: @shift_distance_limit) if color_distance > cache[:max_color_distance] cache[: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 if !@shift_distance_limit || cache[:max_shift_distance] == Float::INFINITY shift_distance = (color_matches && 0) || shift_distance_at(new_img, old_img, x, y, color_distance_limit: @color_distance_limit) if shift_distance && (cache[:max_shift_distance].nil? || shift_distance > cache[:max_shift_distance]) cache[:max_shift_distance] = shift_distance end color_matches end
Source
# File lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb, line 238 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 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, 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, 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 else bounds_breached += 1 end if (y + shift_distance) < new_img.height # bottom ([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) return shift_distance end end else bounds_breached += 1 end if (x + shift_distance) < new_img.width # right ([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 else bounds_breached += 1 end end break if bounds_breached == 4 shift_distance += 1 end Float::INFINITY end
Source
# File lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb, line 212 def skipped_region?(x, y) return false unless @skip_area @skip_area.any? { |region| region.cover?(x, y) } end