{"id":13685844,"url":"https://github.com/dmtrKovalenko/odiff","last_synced_at":"2025-05-01T04:32:24.308Z","repository":{"id":41485432,"uuid":"310022924","full_name":"dmtrKovalenko/odiff","owner":"dmtrKovalenko","description":"The fastest pixel-by-pixel image visual difference tool in the world.","archived":false,"fork":false,"pushed_at":"2025-04-03T14:44:08.000Z","size":57681,"stargazers_count":2144,"open_issues_count":23,"forks_count":83,"subscribers_count":17,"default_branch":"main","last_synced_at":"2025-04-26T14:27:55.479Z","etag":null,"topics":["diff","image-comparison","odiff","pixel-perfect","snapshot","testing-tool","visual"],"latest_commit_sha":null,"homepage":"","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dmtrKovalenko.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"dmtrKovalenko","open_collective":"odiff"}},"created_at":"2020-11-04T14:15:02.000Z","updated_at":"2025-04-24T07:42:57.000Z","dependencies_parsed_at":"2024-04-16T02:30:10.425Z","dependency_job_id":"3fd4538e-a925-44fe-8b78-59ac0f04ac62","html_url":"https://github.com/dmtrKovalenko/odiff","commit_stats":{"total_commits":240,"total_committers":10,"mean_commits":24.0,"dds":0.09166666666666667,"last_synced_commit":"c58c50587d7e55421abbf3ea5c10b2502e74b67f"},"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmtrKovalenko%2Fodiff","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmtrKovalenko%2Fodiff/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmtrKovalenko%2Fodiff/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmtrKovalenko%2Fodiff/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dmtrKovalenko","download_url":"https://codeload.github.com/dmtrKovalenko/odiff/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251802362,"owners_count":21646193,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["diff","image-comparison","odiff","pixel-perfect","snapshot","testing-tool","visual"],"created_at":"2024-08-02T14:00:57.907Z","updated_at":"2025-05-01T04:32:24.301Z","avatar_url":"https://github.com/dmtrKovalenko.png","language":"OCaml","readme":"\u003cp align=\"center\"\u003e\n  \u003cpicture\u003e\n    \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"./odiff-logo-dark.png\"\u003e\n    \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"./odiff-logo-light.png\"\u003e\n    \u003cimg alt=\"pixeletad caml and odiff text with highlighted red pixels difference\" src=\"./odiff-logo-dark.png\"\u003e\n  \u003c/picture\u003e\n\u003c/p\u003e\n\n\u003ch3 align=\"center\"\u003e The fastest* (one-thread) pixel-by-pixel image difference tool in the world. \u003c/h3\u003e\n\n\u003cdiv align=\"center\"\u003e\n    \u003cimg src=\"https://forthebadge.com/images/badges/made-with-reason.svg\" alt=\"made with reason\"\u003e\n    \u003cimg src=\"https://forthebadge.com/images/badges/gluten-free.svg\" alt=\"npm\"/\u003e\n    \u003cimg src=\"https://forthebadge.com/images/badges/powered-by-overtime.svg\"\u003e\n\u003c/div\u003e\n\n\n## Why Odiff?\n\nODiff is a blazing fast native image comparison tool. Check [benchmarks](#benchmarks) for the results, but it compares the visual difference between 2 images in **milliseconds**. It was originally designed to handle the \"big\" images. Thanks to [OCaml](https://ocaml.org/) and its speedy and predictable compiler we can significantly speed up your CI pipeline.\n\n[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://vshymanskyy.github.io/StandWithUkraine/)\n\n## Demo\n\n| base                           | comparison                       | diff                                  |\n| ------------------------------ | -------------------------------- | ------------------------------------- |\n| ![](images/tiger.jpg)          | ![](images/tiger-2.jpg)          | ![1diff](images/tiger-diff.png)       |\n| ![](images/www.cypress.io.png) | ![](images/www.cypress.io-1.png) | ![1diff](images/www.cypress-diff.png) |\n| ![](images/donkey.png)         | ![](images/donkey-2.png)         | ![1diff](images/donkey-diff.png)      |\n\n## Features\n\n- ✅ Cross-format comparison - Yes .jpg vs .png comparison without any problems.\n- ✅ Support for `.png`, `.jpeg`, `.jpg`, and `.tiff`\n- ✅ Supports comparison of images with different layouts.\n- ✅ Anti-aliasing detection\n- ✅ Ignoring regions\n- ✅ Using [YIQ NTSC\n  transmission algorithm](https://progmat.uaem.mx/progmat/index.php/progmat/article/view/2010-2-2-03/2010-2-2-03) to determine visual difference.\n\n### Coming in the nearest future:\n\n- ⏹ Reading image from memory buffer\n- ⏹ Reading images from url \n\n## Usage\n\n### Basic comparison\n\nRun the simple comparison. Image paths can be one of supported formats, diff output is optional and can only be `.png`.\n\n```\nodiff \u003cIMG1 path\u003e \u003cIMG2 path\u003e [DIFF output path]\n```\n\n### Node.js\n\nWe also provides direct node.js binding for the `odiff`. Run the `odiff` from nodejs:\n\n```js\nconst { compare } = require(\"odiff-bin\");\n\nconst { match, reason } = await compare(\n  \"path/to/first/image.png\",\n  \"path/to/second/image.png\",\n  \"path/to/diff.png\"\n);\n```\n\n### Cypress\nCheckout [cypress-odiff](https://github.com/odai-alali/cypress-odiff), a cypress plugin to add visual regression tests using `odiff-bin`.\n\n### Visual regression services\n\n[LostPixel](https://github.com/lost-pixel/lost-pixel) – Holistic visual testing for your Frontend allows very easy integration with storybook and uses odiff for comparison\n\n[Argos CI](https://argos-ci.com/) – Visual regression service powering projects like material-ui. ([It became 8x faster with odiff](https://twitter.com/argos_ci/status/1601873725019807744))\n\n[Visual Regression Tracker](https://github.com/Visual-Regression-Tracker/Visual-Regression-Tracker) – Self hosted visual regression service that allows to use odiff as screenshot comparison engine \n\n[OSnap](https://github.com/eWert-Online/OSnap) – Snapshot testing tool written in OCaml that uses config based declaration to define test and was built by odiff collaborator. \n\n## Api\n\nHere is an api reference:\n\n### CLI\n\nThe best way to get up-to-date cli interface is just to type the\n\n```\nodiff --help\n```\n\n### Node.js\n\nNodeJS Api is pretty tiny as well. Here is a typescript interface we have:\n\n\u003c!--inline-interface-start--\u003e\n```tsx\nexport type ODiffOptions = Partial\u003c{\n  /** Color used to highlight different pixels in the output (in hex format e.g. #cd2cc9). */\n  diffColor: string;\n  /** Output full diff image. */\n  outputDiffMask: boolean;\n  /** Do not compare images and produce output if images layout is different. */\n  failOnLayoutDiff: boolean;\n  /** Return { match: false, reason: '...' } instead of throwing error if file is missing. */\n  noFailOnFsErrors: boolean;\n  /** Color difference threshold (from 0 to 1). Less more precise. */\n  threshold: number;\n  /** If this is true, antialiased pixels are not counted to the diff of an image */\n  antialiasing: boolean;\n  /** If `true` reason: \"pixel-diff\" output will contain the set of line indexes containing different pixels */\n  captureDiffLines: boolean;\n  /** If `true` odiff will use less memory but will be slower with larger images */\n  reduceRamUsage: boolean;\n  /** An array of regions to ignore in the diff. */\n  ignoreRegions: Array\u003c{\n    x1: number;\n    y1: number;\n    x2: number;\n    y2: number;\n  }\u003e;\n}\u003e;\n\ndeclare function compare(\n  basePath: string,\n  comparePath: string,\n  diffPath: string,\n  options?: ODiffOptions\n): Promise\u003c\n  | { match: true }\n  | { match: false; reason: \"layout-diff\" }\n  | {\n      match: false;\n      reason: \"pixel-diff\";\n      /** Amount of different pixels */\n      diffCount: number;\n      /** Percentage of different pixels in the whole image */\n      diffPercentage: number;\n      /** Individual line indexes containing different pixels. Guaranteed to be ordered and distinct.  */\n      diffLines?: number[];\n    }\n  | {\n      match: false;\n      reason: \"file-not-exists\";\n      /** Errored file path */\n      file: string;\n    }\n\u003e;\n\nexport { compare };\n```\n\u003c!--inline-interface-end--\u003e\"\n \nCompare option will return `{ match: true }` if images are identical. Otherwise return `{ match: false, reason: \"*\" }` with a reason why images were different.\n\n\u003e Make sure that diff output file will be created only if images have pixel difference we can see 👀\n\n## Installation\n\nWe provide prebuilt binaries for most of the used platforms, there are a few ways to install them: \n\n### Cross-platform\n\nThe recommended and cross-platform way to install this lib is npm and node.js. Make sure that this package is compiled directly to the platform binary executable, so the npm package contains all binaries and `post-install` script will automatically link the right one for the current platform.\n\n\u003e **Important**: package name is **odiff-bin**. But the binary itself is **odiff**\n\n```\nnpm install odiff-bin\n```\n\nThen give it a try 👀\n\n```\nodiff --help\n```\n\n### From binaries\n\nDownload the binaries for your platform from [release](https://github.com/dmtrKovalenko/odiff/releases) page.\n\n## Benchmarks\n\n\u003e Run the benchmarks by yourself. Instructions of how to run the benchmark is [here](./images)\n\n![benchmark](images/benchmarks.png)\n\nPerformance matters. At least for sort of tasks like visual regression. For example, if you are running 25000 image snapshots per month you can save **20 hours** of CI time per month by speeding up comparison time in just **3 seconds** per snapshot.\n\n```\n3s * 25000 / 3600 = 20,83333 hours\n```\n\nHere is `odiff` performance comparison with other popular visual difference solutions. We are going to compare some real-world use cases.\n\nLets compare 2 screenshots of full-size [https::/cypress.io](cypress.io) page:\n\n| Command                                                                                    |      Mean [s] | Min [s] | Max [s] |    Relative |\n| :----------------------------------------------------------------------------------------- | ------------: | ------: | ------: | ----------: |\n| `pixelmatch www.cypress.io-1.png www.cypress.io.png www.cypress-diff.png`                  | 7.712 ± 0.069 |   7.664 |   7.896 | 6.67 ± 0.03 |\n| ImageMagick `compare www.cypress.io-1.png www.cypress.io.png -compose src diff-magick.png` | 8.881 ± 0.121 |   8.692 |   9.066 | 7.65 ± 0.04 |\n| `odiff www.cypress.io-1.png www.cypress.io.png www.cypress-diff.png`                       | 1.168 ± 0.008 |   1.157 |   1.185 |        1.00 |\n\nWow. Odiff is mostly 6 times faster than imagemagick and pixelmatch. And this will be even clearer if image will become larger. Lets compare an [8k image](images/water-4k.png) to find a difference with [another 8k image](images/water-4k-2.png):\n\n| Command                                                                       |       Mean [s] | Min [s] | Max [s] |    Relative |\n| :---------------------------------------------------------------------------- | -------------: | ------: | ------: | ----------: |\n| `pixelmatch water-4k.png water-4k-2.png water-diff.png`                       | 10.614 ± 0.162 |  10.398 |  10.910 | 5.50 ± 0.05 |\n| Imagemagick `compare water-4k.png water-4k-2.png -compose src water-diff.png` |  9.326 ± 0.436 |   8.819 |  10.394 | 5.24 ± 0.10 |\n| `odiff water-4k.png water-4k-2.png water-diff.png`                            |  1.951 ± 0.014 |   1.936 |   1.981 |        1.00 |\n\nYes it is significant improvement. And the produced difference will be the same for all 3 commands.\n\n## Changelog\n\nIf you have recently updated, please read the [changelog](https://github.com/dmtrKovalenko/odiff/releases) for details of what has changed.\n\n## License\n\nThe project is licensed under the terms of [MIT license](./LICENSE)\n\n## Thanks\n\nThis project was highly inspired by [pixelmatch](https://github.com/mapbox/pixelmatch) and [imagemagick](https://github.com/ImageMagick/ImageMagick).\n\n## Support the project\n\n...one day a donation button will appear here. But for now you can follow [author's twitter](https://twitter.com/dmtrKovalenko) :)\n","funding_links":["https://github.com/sponsors/dmtrKovalenko","https://opencollective.com/odiff"],"categories":["\u003ca name='Repositories'\u003e\u003c/a\u003eRepositories","Algorithms and Data Structures","Reason","Zig","Multimedia \u0026 Graphics"],"sub_categories":["\u003ca name='ImageProcessing'\u003e\u003c/a\u003eImage Processing","Image and Video Processing"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FdmtrKovalenko%2Fodiff","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FdmtrKovalenko%2Fodiff","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FdmtrKovalenko%2Fodiff/lists"}