Skip to content

Commit a8716a3

Browse files
pftgclaude
andcommitted
feat: add Diff.compare for standalone image comparison
Browser-independent API for comparing any two images: result = Capybara::Screenshot::Diff.compare("a.png", "b.png") result.quick_equal? # byte-identical? result.different? # visually different? Supports all existing options (driver, tolerance, perceptual_threshold). Based on real usage from corsis/pet which uses the gem for PDF regression. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 076cbac commit a8716a3

3 files changed

Lines changed: 81 additions & 0 deletions

File tree

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,23 @@ end
155155
| Standard Rails apps | 0.0005 | 15 | 1s |
156156
| Pixel-perfect design tests | 0.0001 | 5 | 1s |
157157

158+
### Standalone image comparison
159+
160+
Compare any two images without Capybara or a browser — useful for PDF regression, generated images, or CI artifact validation:
161+
162+
```ruby
163+
result = Capybara::Screenshot::Diff.compare("baseline.png", "current.png")
164+
result.quick_equal? # => true if byte-identical
165+
result.different? # => true if visually different (respects tolerance)
166+
167+
# With options
168+
result = Capybara::Screenshot::Diff.compare("baseline.pdf.png", "current.pdf.png",
169+
driver: :vips,
170+
tolerance: 0.001,
171+
perceptual_threshold: 2.0
172+
)
173+
```
174+
158175
### Perceptual color comparison (VIPS only)
159176

160177
By default, color differences are measured using raw RGB channel distance. This can produce

lib/capybara_screenshot_diff.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ def self.configure
9090
yield Screenshot, self
9191
end
9292

93+
def self.compare(baseline_path, current_path, **options)
94+
ImageCompare.new(current_path, baseline_path, default_options.merge(options))
95+
end
96+
9397
def self.default_options
9498
{
9599
area_size_limit: area_size_limit,

test/unit/compare_api_test.rb

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# frozen_string_literal: true
2+
3+
require "test_helper"
4+
5+
module Capybara
6+
module Screenshot
7+
module Diff
8+
class CompareApiTest < ActiveSupport::TestCase
9+
test ".compare returns ImageCompare instance" do
10+
result = Diff.compare(
11+
TEST_IMAGES_DIR / "a.png",
12+
TEST_IMAGES_DIR / "a.png"
13+
)
14+
assert_kind_of ImageCompare, result
15+
end
16+
17+
test ".compare detects identical images" do
18+
result = Diff.compare(
19+
TEST_IMAGES_DIR / "a.png",
20+
TEST_IMAGES_DIR / "a.png"
21+
)
22+
assert result.quick_equal?
23+
assert_not result.different?
24+
end
25+
26+
test ".compare detects different images" do
27+
result = Diff.compare(
28+
TEST_IMAGES_DIR / "a.png",
29+
TEST_IMAGES_DIR / "b.png"
30+
)
31+
assert_not result.quick_equal?
32+
assert result.different?
33+
end
34+
35+
test ".compare accepts driver option" do
36+
skip "VIPS not present" unless defined?(Vips)
37+
38+
result = Diff.compare(
39+
TEST_IMAGES_DIR / "a.png",
40+
TEST_IMAGES_DIR / "a.png",
41+
driver: :vips
42+
)
43+
assert result.quick_equal?
44+
end
45+
46+
test ".compare accepts tolerance options" do
47+
skip "VIPS not present" unless defined?(Vips)
48+
49+
result = Diff.compare(
50+
TEST_IMAGES_DIR / "a.png",
51+
TEST_IMAGES_DIR / "b.png",
52+
driver: :vips,
53+
tolerance: 1.0
54+
)
55+
assert_not result.different?
56+
end
57+
end
58+
end
59+
end
60+
end

0 commit comments

Comments
 (0)