BlazeDiff

repository·main·Indexed 43 days ago

https://github.com/teimurjan/blazediff

A high-performance diff ecosystem for pixel-perfect image comparison, structured diff analysis, and object diffing. It provides optimized implementations across JavaScript (WASM/JS), Rust, and Python, featuring the blazediff-interpret crate for structured region analysis and the blazediff-png SIMD-first PNG codec.

Tokens
167.6K
Snippets
570
Records
781
Agent score
51%

What's inside BlazeDiff

  1. Overview of BlazeDiff Benchmark Targets

    main

    BlazeDiff provides performance benchmarks across three primary domains to compare its speed and efficiency against industry-standard alternatives. The benchmarks are categorized into Pixel By Pixel, Structural Similarity, and Object Diffing.

    Benchmark Categories

    1. Pixel By Pixel Diffing: Compares @blazediff/core (JS), @blazediff/core-wasm, @blazediff/core-native, and the blazediff PyPI bindings against pixelmatch, odiff, and opencv-python.
    2. Structural Similarity (SSIM): Compares @blazediff/ssim (fast/original + hitchhikers) and @blazediff/ssim-native against ssim.js (fast + weber).
    3. Object Diffing: Compares @blazediff/object against microdiff.

    Benchmark results are presented in summary charts where orange indicates BlazeDiff is faster and magenta indicates a regression.

  2. Overview of blazediff-png

    main

    blazediff-png is a high-performance, single-threaded, SIMD-first PNG codec written in Rust. It is designed to be a faster replacement for libspng while maintaining byte-exact decode compatibility. It is optimized for speed on a single core, allowing callers to handle parallelization across multiple images.

    Key Capabilities

    • Decoding: Supports all formats accepted by spng (bit depths 1/2/4/8/16, all five color types, palette + tRNS, gray/RGB color-key transparency, and Adam7 interlacing) to RGBA8. It can target specific SPNG_FMT_* formats with optional gamma/sBIT transforms and capture ancillary chunks via decode_with_metadata.
    • Encoding: Supports all color-type/bit-depth combinations, optional Adam7, and real deflate levels (via libdeflate) plus a stored level 0. The codec is lossless by construction.
    • Performance: Outperforms spng in both decode (~1.4x) and encode (~3.8x for compressed) tasks on tested fixtures.
  3. Overview of BlazeDiff packages and capabilities

    main

    BlazeDiff is a high-performance diff ecosystem providing tools for image comparison, structured diff analysis, object diffing, and perceptual quality metrics.

    Core Libraries

    • @blazediff/core-native: Fastest single-threaded image diff (Rust + SIMD).
    • @blazediff/core-wasm: WebAssembly build for browsers and edge runtimes.
    • @blazediff/core: Pixel-perfect image comparison (JS).
    • @blazediff/interpret-native: Structured Rust interpretation of diff regions (what/where/how much).
    • @blazediff/object: High-performance object diffing.
    • @blazediff/ssim: SSIM, MS-SSIM, and Hitchhiker's SSIM metrics.
    • @blazediff/ssim-native: Native Rust implementation of SSIM metrics.
    • @blazediff/gmsd: Gradient Magnitude Similarity Deviation metric.

    Command Line Tools

    • @blazediff/cli: JS CLI supporting multiple algorithms (diff, GMSD, SSIM, MS-SSIM, Hitchhiker's SSIM).
    • @blazediff/agent: Agentic visual regression tool for auto-discovering routes and capturing screenshots.

    UI Components

    • @blazediff/react: React components for visualizing differences.
    • @blazediff/ui: Headless engine and framework-agnostic renderer for image-diff UIs.
  4. Use blazediff-shared for image I/O and YIQ color math

    main

    The blazediff-shared crate provides the core primitives used across the BlazeDiff ecosystem, including the RGBA8 Image buffer, YIQ color math for perceptual distance, and support for PNG, JPEG, and QOI formats.

    Core Concepts

    • Image Buffer: The Image type represents an RGBA8 buffer (4 bytes per pixel) in row-major order.
    • Perceptual Metric: Uses YIQ color space math via yiq::color_delta to measure squared distance between pixels, which is the foundation for both pixel diffing and region classification.
    • Format Detection: Formats are automatically detected from file extensions (for paths) or magic bytes (for byte buffers).
    use blazediff_shared::{load_image_pair, save_image, Image, ImageFormat};
    
    let (a, b) = load_image_pair("expected.png", "actual.jpg")?;
    println!("{}x{}", a.width, a.height);
    
    // `Image` is RGBA8, 4 bytes per pixel, row-major.
    let out = Image::new(a.width, a.height);
    save_image(&out, "diff.png", /* compression */ 0, /* quality */ 90)?;
  5. Compare images with @blazediff/core-native

    main

    The @blazediff/core-native package provides high-performance image comparison capabilities. It supports various image formats and provides detailed diff outputs using advanced color space models like YIQ and anti-aliasing detection algorithms.

    Core API: compare function

    The primary way to use the library is via the compare function, which takes a base image, a comparison image, and an output destination.

    Signature: compare(base, comparison, diffOutput, options?)

    • base: The original image to compare against.
    • comparison: The new image to check for differences.
    • diffOutput: The destination where the diff image/data will be written.
    • options?: Optional configuration for the comparison behavior.

    Result Types

    The comparison process produces structured results that describe the nature of the differences found between the two images.

    // Example of the core compare signature
    compare(base, comparison, diffOutput, options);
  6. GMSD Algorithm Implementation Steps

    main

    The GMSD calculation follows these four primary steps:

    1. Downsample (optional): Apply a 2×2 averaging filter, then subsample by 2 to reduce resolution.
    2. Compute gradients: Apply the Prewitt operator to both the reference and distorted images to extract gradient maps.
    3. Calculate similarity map: Compute the Gradient Magnitude Similarity (GMS) for every pixel.
    4. Return deviation: Calculate the standard deviation of the resulting GMS map to produce the final GMSD score.
  7. Choosing the right @blazediff/cli algorithm

    main

    Select an algorithm based on your specific use case:

    AlgorithmBest for
    core-nativeMaximum speed, CI/CD, large images
    coreCustom diff colors, color space control, no native deps
    gmsdSimilarity score, compression-tolerant
    ssimMATLAB-compatible, research
    msssimMulti-scale, varying resolutions
    hitchhikers-ssimFast SSIM (~4x), large batches
  8. Use Harnesses to drive page interactions

    main

    A harness is a pluggable ESM module (.js or .mjs) located in .blazediff/harnesses/<name>.js that executes logic before or during a screenshot capture. Harnesses allow you to perform complex flows like opening menus or switching tabs.

    There are two phases:

    1. setup: Runs before navigation (e.g., to establish a session or login).
    2. interact (default): Runs after the base screenshot. It can drive the page and emit additional named screenshots using screenshot(name). These additional shots become separate entries in the manifest with the ID format <entry>__<name>.

    To use an interaction harness, attach it to an entry in the manifest by its name.

    // .blazediff/harnesses/weather-menu.js
    /** @type {import("@blazediff/agent").Harness} */
    export default {
      async run({ page, screenshot }) {
        await page.getByRole("button", { name: "More options" }).click();
        await screenshot("menu"); // -> baseline "weather__menu"
      },
    };
  9. Use harnesses to drive page interactions and sub-screenshots

    main

    A harness is a pluggable script located in .blazediff/harnesses/<name>.js that allows you to automate page interactions and capture multiple screenshots for a single entry.

    There are two execution phases:

    1. setup: Runs before navigation (e.g., for establishing a session or logging in). This phase must not call screenshot().
    2. interact (default): Runs after the base screenshot is taken. This phase drives the page and can emit additional named screenshots.

    When you call screenshot("name") inside an interact harness, it creates a sub-baseline/diff entry with the ID <parent-id>__name.

    Implementation Details:

    • Harnesses must be ESM modules that default-export a Harness object.
    • TypeScript is not auto-transpiled; use .js or .mjs files and the @type {import("@blazediff/agent").Harness} JSDoc annotation for intellisense.
    • Screenshot names must be alphanumeric or kebab-case (no spaces, slashes, or double underscores).
    • To re-run a harness and regenerate all its child screenshots, use the command rewrite <parent-id>.
    /** @type {import("@blazediff/agent").Harness} */
    export default {
      // phase defaults to "interact": runs AFTER the base screenshot.
      async run({ page, screenshot }) {
        await page.getByRole("button", { name: "More options" }).click();
        await screenshot("menu");   // -> a sub-baseline with id "<entry>__menu"
      },
    };
  10. Apply shared masks using data attributes

    main

    To mask specific UI elements (like live metrics or dynamic data) across all applications in a monorepo, use the data-blazediff-agent-mask attribute. By placing this attribute on a shared component (e.g., in packages/ui), every application that renders that component will automatically inherit the mask without needing to update individual app manifests.

    <div data-blazediff-agent-mask="live-metrics">...</div>