The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Getting Started with Odiffr

Introduction

Odiffr provides R bindings to Odiff, a blazing-fast pixel-by-pixel image comparison tool. It’s designed for:

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

If you cannot install Odiff system-wide, use odiffr_update() after installing the package to download a binary to your user cache.

Installation

# From CRAN (when available)
install.packages("odiffr")

# Development version
pak::pak("BenWolst/odiffr")

Basic Usage

library(odiffr)

Check Configuration

# Verify Odiff is available
odiff_available()
#> [1] TRUE

# View configuration details
odiff_info()
#> odiffr configuration
#> --------------------
#> OS:       darwin 
#> Arch:     arm64 
#> Path:     /opt/homebrew/lib/node_modules/odiff-bin/raw_binaries/odiff-macos-arm64 
#> Version:  <unknown> 
#> Source:   system

Compare Images

The main function is compare_images(), which returns a tibble (or data.frame):

result <- compare_images("baseline.png", "current.png")
result
#> # A tibble: 1 × 7
#>   match reason     diff_count diff_percentage diff_output img1         img2
#>   <lgl> <chr>           <int>           <dbl> <chr>       <chr>        <chr>
#> 1 FALSE pixel-diff       1234            2.45 NA          baseline.png current.png

Generate Diff Images

# Specify output path
result <- compare_images("baseline.png", "current.png",
                         diff_output = "diff.png")

# Or use TRUE for auto-generated temp file
result <- compare_images("baseline.png", "current.png",
                         diff_output = TRUE)
result$diff_output
#> [1] "/tmp/RtmpXXXXXX/file12345.png"

Advanced Options

Threshold

The threshold parameter (0-1) controls color sensitivity. Lower values are more precise:

# Very strict comparison
result <- compare_images("img1.png", "img2.png", threshold = 0.01)

# More lenient (ignore minor color variations)
result <- compare_images("img1.png", "img2.png", threshold = 0.2)

Antialiasing

Ignore antialiased pixels that often differ between renders:

result <- compare_images("img1.png", "img2.png", antialiasing = TRUE)

Ignore Regions

Exclude specific areas from comparison (useful for timestamps, dynamic content):

result <- compare_images("img1.png", "img2.png",
  ignore_regions = list(
    ignore_region(x1 = 0, y1 = 0, x2 = 200, y2 = 50),    # Header
    ignore_region(x1 = 0, y1 = 900, x2 = 1920, y2 = 1080) # Footer
  )
)

Batch Processing

Compare multiple image pairs efficiently:

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

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

# View failures
results[!results$match, ]

Working with magick

Odiffr integrates with the magick package for preprocessing:

library(magick)

# Read and preprocess images
img1 <- image_read("baseline.png") |>
  image_resize("800x600") |>
  image_convert(colorspace = "sRGB")

img2 <- image_read("current.png") |>
  image_resize("800x600") |>
  image_convert(colorspace = "sRGB")

# Compare directly
result <- compare_images(img1, img2)

Low-Level API

For full control, use odiff_run():

result <- odiff_run(
  img1 = "baseline.png",
  img2 = "current.png",
  diff_output = "diff.png",
  threshold = 0.1,
  antialiasing = TRUE,
  fail_on_layout = TRUE,
  diff_mask = FALSE,
  diff_overlay = 0.5,
  diff_color = "#FF00FF",
  diff_lines = TRUE,
  reduce_ram = FALSE,
  ignore_regions = list(ignore_region(10, 10, 100, 50)),
  timeout = 60
)

# Detailed result
result$match
result$reason
result$diff_count
result$diff_percentage
result$diff_lines
result$exit_code
result$duration

Binary Management

Update Binary

Download the latest Odiff binary to your user cache:

# Latest version
odiffr_update()

# Specific version
odiffr_update(version = "v4.1.2")

Custom Binary Path

Use a specific binary (useful for validated environments):

options(odiffr.path = "/validated/bin/odiff-4.1.2")

Cache Management

# View cache location
odiffr_cache_path()
#> [1] "/Users/benwolstenholme/Library/Caches/org.R-project.R/R/odiffr"
# Clear cached binaries
odiffr_clear_cache()

Visual Regression Testing

Example integration with testthat:

library(testthat)
library(odiffr)

test_that("dashboard renders correctly", {
  # Generate current screenshot
  webshot2::webshot("http://localhost:3838/dashboard", "current.png")

  # Compare to baseline
  result <- compare_images(
    "baselines/dashboard.png",
    "current.png",
    diff_output = "diffs/dashboard_diff.png",
    threshold = 0.1,
    antialiasing = TRUE
  )

  expect_true(result$match,
    info = sprintf("%.2f%% pixels differ", result$diff_percentage))
})

For Validated Environments

Odiffr is designed for validated pharmaceutical/clinical research:

  1. Pinnable: Lock to a specific validated binary with options(odiffr.path = ...)
  2. Auditable: Use odiff_version() to document binary version for audit trails
  3. Base R core: Zero external runtime dependencies for core functions
# Pin to a specific validated binary
options(odiffr.path = "/validated/bin/odiff-4.1.2")

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

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.