VPSPulse Mirrors

High-Performance Open-Source Archive

README

Odiffr Odiffr logo

CRAN status R-CMD-check Codecov

Fast pixel-by-pixel image comparison for R, powered by odiff.

Features

Installation

System Requirements

Odiffr requires the Odiff binary to be installed on your system:

# npm (cross-platform, recommended)
npm install -g odiff-bin

# Or download binaries from GitHub releases
# https://github.com/dmtrKovalenko/odiff/releases

Install Odiffr

# Install from CRAN (when available)
install.packages("odiffr")

# Or install the development version from GitHub
# install.packages("pak")
pak::pak("BenWolst/odiffr")

Alternative: Download via R

If you cannot install Odiff system-wide:

odiffr::odiffr_update()  # Downloads to user cache

Quick Start

library(odiffr)

# Compare two images
result <- compare_images("baseline.png", "current.png")
result$match
#> [1] FALSE

result$diff_percentage
#> [1] 2.45

# Generate a diff image
result <- compare_images("baseline.png", "current.png", diff_output = "diff.png")

Usage

Basic Comparison

# High-level API (returns tibble if available)
result <- compare_images("img1.png", "img2.png")

# Low-level API (returns detailed list)
result <- odiff_run("img1.png", "img2.png")

With Options

# Adjust sensitivity threshold (0-1, lower = more precise)
result <- compare_images("img1.png", "img2.png", threshold = 0.05)

# Ignore antialiased pixels
result <- compare_images("img1.png", "img2.png", antialiasing = TRUE)

# Fail immediately if dimensions differ
result <- compare_images("img1.png", "img2.png", fail_on_layout = TRUE)

Ignore Regions

# Ignore specific areas (e.g., timestamps, dynamic content)
result <- compare_images("img1.png", "img2.png",
  ignore_regions = list(
    ignore_region(0, 0, 200, 50),     # Header
    ignore_region(0, 500, 800, 600)   # Footer
  )
)

Batch Comparison

# Compare multiple image pairs
pairs <- data.frame(
  img1 = c("baseline/page1.png", "baseline/page2.png"),
  img2 = c("current/page1.png", "current/page2.png")
)

results <- compare_images_batch(pairs, diff_dir = "diffs/")

# Extract failures or passes
failed_pairs(results)
passed_pairs(results)

# Compare entire directories
results <- compare_image_dirs("baseline/", "current/", recursive = TRUE)

# Get summary statistics
summary(results)
#> odiffr batch comparison: 50 pairs
#> Passed: 42 (84.0%)
#> Failed: 8 (16.0%)

# Use parallel processing (Unix only)
results <- compare_images_batch(pairs, parallel = TRUE)

HTML Reports

# One-liner: compare directories and generate HTML report
compare_dirs_report("baseline/", "current/")
# -> Creates diffs/ directory with diff images and report.html

# Or step-by-step for more control
results <- compare_image_dirs("baseline/", "current/", diff_dir = "diffs/")
batch_report(results, output_file = "qa-report.html")

# Self-contained report with embedded images
batch_report(results, output_file = "qa-report.html", embed = TRUE)

# Portable report with relative image paths
batch_report(results, output_file = "output/report.html", relative_paths = TRUE)

CI Integration

Run visual regression tests in GitHub Actions and upload diff artifacts:

# .github/workflows/visual-regression.yaml
name: Visual Regression

on: [push, pull_request]

jobs:
  visual-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: r-lib/actions/setup-r@v2

      - name: Install dependencies
        run: |
          install.packages(c("odiffr", "webshot2"))
          odiffr::odiffr_update()
        shell: Rscript {0}

      - name: Generate screenshots
        run: Rscript scripts/generate-screenshots.R

      - name: Compare images
        run: |
          library(odiffr)
          results <- compare_dirs_report("baseline/", "current/")
          if (any(!results$match)) stop("Visual regression detected!")
        shell: Rscript {0}

      - name: Upload diffs
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: visual-diffs
          path: diffs/

With magick Package

library(magick)

# Compare magick-image objects directly
img1 <- image_read("baseline.png") |> image_resize("800x600")
img2 <- image_read("current.png") |> image_resize("800x600")

result <- compare_images(img1, img2)

Visual Regression Testing

library(testthat)
library(odiffr)

test_that("dashboard renders correctly", {

  expect_images_match(
    "screenshots/current.png",
    "screenshots/baseline.png",
    threshold = 0.1
  )
})

test_that("button changes on hover", {
  expect_images_differ(
    "button_normal.png",
    "button_hover.png"
  )
})

On failure, diff images are automatically saved to tests/testthat/_odiffr/.

Binary Management

# Check if Odiff is available
odiff_available()

# Get version and configuration info
odiff_info()

# Update to latest version (downloads to user cache)
odiffr_update()

# Use a specific binary
options(odiffr.path = "/path/to/odiff")

Binary Detection Priority

  1. options(odiffr.path = "...") - User override
  2. System PATH (Sys.which("odiff"))
  3. Cached binary from odiffr_update()

Supported Formats

Type Formats
Input PNG, JPEG, WEBP, TIFF
Output PNG only

Cross-format comparison is supported (e.g., compare JPEG to PNG).

For Validated Environments

Odiffr is designed for use in validated pharmaceutical and clinical research:

# Pin to a specific validated binary
options(odiffr.path = "/validated/bin/odiff-4.1.2")

# Document in validation scripts
info <- odiff_info()
sprintf("Using odiff %s from %s", info$version, info$source)

Performance

Odiff is approximately 6x faster than ImageMagick for pixel comparison, thanks to SIMD optimizations. Performance scales well with image size.

License

MIT

Need mirroring services?
Contact our team at info@vpspulse.com.

Mirror powered by VPSpulse

Infrastructure sponsored by VPSPulse & Secure Payments by ArionPay.