---
title: "Getting Started with Odiffr"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Getting Started with Odiffr}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  eval = odiffr::odiff_available()
)
```

## Introduction
Odiffr provides R bindings to [Odiff](https://github.com/dmtrKovalenko/odiff),
a blazing-fast pixel-by-pixel image comparison tool. It's designed for:

- Visual regression testing of Shiny apps and reports
- Quality assurance in validated pharmaceutical environments
- Automated image analysis workflows

## System Requirements

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

```bash
# 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

```{r eval=FALSE}
# From CRAN (when available)
install.packages("odiffr")

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

## Basic Usage

```{r setup}
library(odiffr)
```

### Check Configuration

```{r}
# Verify Odiff is available
odiff_available()

# View configuration details
odiff_info()
```

### Compare Images

The main function is `compare_images()`, which returns a tibble (or data.frame):
```{r eval=FALSE}
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

```{r eval=FALSE}
# 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:

```{r eval=FALSE}
# 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:

```{r eval=FALSE}
result <- compare_images("img1.png", "img2.png", antialiasing = TRUE)
```

### Ignore Regions

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

```{r eval=FALSE}
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:

```{r eval=FALSE}
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](https://cran.r-project.org/package=magick)
package for preprocessing:

```{r eval=FALSE}
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()`:

```{r eval=FALSE}
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:

```{r eval=FALSE}
# Latest version
odiffr_update()

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

### Custom Binary Path

Use a specific binary (useful for validated environments):

```{r eval=FALSE}
options(odiffr.path = "/validated/bin/odiff-4.1.2")
```

### Cache Management

```{r}
# View cache location
odiffr_cache_path()
```

```{r eval=FALSE}
# Clear cached binaries
odiffr_clear_cache()
```

## Visual Regression Testing

Example integration with testthat:

```{r eval=FALSE}
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

```{r eval=FALSE}
# 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)
```
