dmtrkovalenko / odiff Goto Github PK
View Code? Open in Web Editor NEWThe fastest pixel-by-pixel image visual difference tool in the world.
License: MIT License
The fastest pixel-by-pixel image visual difference tool in the world.
License: MIT License
I'm trying to integrate odiff into a third-party lib. It would be great if the compare function would also accept buffers instead of paths. This would save the round trip to write a buffer to disk in some use cases.
is it possible to use remote image urls as inputs and save diff in buffer so i can save it remotely instead of writing to file?
How do I draw different pixels to the grayscale image of the original image?Because I think the difference pixels look clearer in grayscale images.
(async () => {
const result = await odiff.compare(
getImagePath("1.png"),
getImagePath("diffLayout2.png"),
getImagePath("diff.png"),
{
antialiasing: true
}
);
console.log(result);
})();
(node:74741) UnhandledPromiseRejectionWarning: TypeError: odiff: option `--antialiasing' is a flag, it cannot take the argument `true'
at ChildProcess.<anonymous> (.../node_modules/odiff-bin/odiff.js:123:13)
at ChildProcess.emit (events.js:327:22)
at maybeClose (internal/child_process.js:1021:16)
at Socket.<anonymous> (internal/child_process.js:443:11)
at Socket.emit (events.js:315:20)
at Pipe.<anonymous> (net.js:674:12)
The benchmark in the README.MD mentions "Pixelmatch", and shows a graph comparing Odiff, ImageMagick and Pixelmatch.
However the benchmark includes the PNG decoding, image diffing, and finally PNG encoding of the diff image. Given the resolution of the images, the PNG codec will take a significant share of the time.
It would be more fair to say "Pixelmatch + pngjs" together.
As in topic.
(base) wenke@wenkedeMac-mini odiff-e7f41c97 % odiff 20201123/N_0_2006255981_B.bmp 20201123/N_0_2006255981_T.bmp 1.png
hang on there with no result at all , two image are all 300kb
download source code and run npm install ,rename bin/ODiffBin to odiff ,add this bin path to zsh
Would you be open to the idea of publishing the diff code (everything located under src) to opam?
Or at least separate it into its own opam library, so you can install it using esy without installing all requirements needed for the io part.
Some background:
I am currently working on a snapshot testing library, using odiff.
Right now, installing odiff with esy also installs everything needed for the io package, which I don't use.
So it would be great to be able to just install the diff part.
I am trying to use odiff in the CI pipeline of a plotting tool I maintain called NicePlots to test that the images output by our examples remain consistent. We are running into the issue that, even using the --antialiasing
command line option, we still have images differing on very small numbers of pixels due to what I assume are slight differences in anti-aliasing on different systems.
Here's an example from one of our recent CI runs:
odiff --aa --threshold=0.1 --dm doumont-light_style_demo_reference.png doumont-light_style_demo.png doumont-light_style_demo-diff.png
Failure! Images are different.
Different pixels: 386 (0.003490%)
In our case, these minor differences are not the kind of thing we're looking to catch with our tests. We tried playing around with the --threshold
option but found we had to make it impractically high to get past these issues.
It would be extremely useful to be able to specify that a certain percentage of differing pixels (e.g <= 0.01%) is acceptable, by adding a command line option like --tolerance=0.01
.
Thanks to this tweet https://twitter.com/jhaynes9/status/1327416823629967364?s=21 I realized that alpine package really doesn’t work — fix this
not sure why it's not working
here is the repo to reproduce
https://github.com/pashidlos/image-compare-tryouts/blob/main/src/odiff.js
node src/odiff.js
(node:24395) UnhandledPromiseRejectionWarning: Error: dyld: Library not loaded: _____________________________________________________________________________________/i/esy_libpng-635d6ecc/lib/libpng16.16.dylib
Referenced from: /Users/pashidlos/work/image-compare-try/node_modules/odiff-bin/3/i/odiff-4d94fb12/bin/ODiffBin
Reason: image not found
Hi,
nice project, but I did not find information if it can show the difference in percentage how two images differ?
Why I ask that?
For example I have more then 2000 wallpapers and some of them are places there twice, with different resolutions and file names but they are generally the same image. It would be nice if odiff would show that image X is 97% the same as image Y.
Just an idea.
Regards.
Hello, I'm using odiff with cypress. Everything is working fine, but only in Jenkins, I'm getting the following error in some scenarios (not in all scenarios):
CypressError: cy.task('compare')
failed with the following error:
odiff: internal error, uncaught exception:
Failure("Can not save the output :(")
Do you have any idea why is this happened?
*When the scenarios run locally with docker, this error never appeared. I face this error only in Jenkins
Could you provide darwin arm64 build?
In order to ignore some parts of an image it would be useful pass them as array of objects
{
x: number;
y: number;
width: number;
height: number;
}
First off, I gotta say, I love this thing. Thank you so much for your work!
I'm currently using it as a dependency for my own open source Node project and it works perfectly on Windows but on a Mac I actually have to go into the node_modules/odiff-bin dependency folder and explicitly do an "npm install" or it won't work (I think it doesn't automatically copy the binary into the bin folder).
While it works locally, it fails to install on our CI Jenkins (Windows):
package.json:
"dependencies": { "odiff-bin": "^2.1.1" }
log:
[email protected] postinstall C:\Jenkins\workspace\Web\CubeMobileApps@3\Webpages\CubeMobileApps\node_modules\odiff-bin
node ./postinstall.js
Couldn't find C:\Jenkins\workspace\Web\CubeMobileApps@3\Webpages\CubeMobileApps\node_modules\odiff-bin\platform-windows-x64\bin\odiff trying with .exe
error: Esy prefix path is too deep in the filesystem, Esy won't be able to relocate artefacts
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] postinstall:node ./postinstall.js
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] postinstall script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
As this is a shared CI setup with other projects, we can't change the directory containing the pipeline workspaces.
Would be nice to be able to not save the diffOutput. I just need the diff info :)
By default the screenshot which are taken are having the resolution of 1503x791 px ( When my PC resolution is 1920x1080)
And if we reduce display resolution in PC and the resolution of screenshots taken is varying.
Is there any way to fix this and make this independent of screen resolution.
Thanks!
Hi,
Problem: sometimes diff image is really small and it's hard to understand the difference between current and reference images.
Proposal: allow to generate diff2 image that add diff-mask above the reference image;
Proposal 2: mark such differences somehow if there are small (circle around them or so);
Of course, if the reference image has a lot of red it could be a problem (because diff-image is always red), so we need also a parameter for diff-image color.
Thanks in advance :)
Hi,
We're currently experiencing some issues with small differences in our images. These are always related to fonts that have a few pixels different. Although the config is passing antialiasing: true
, it still fails the comparison.
To give some background, the base images are created on a Windows OS. The actual comparison is run through Cypress on a Linux VM.
I have taken the liberty to include the images that are causing these issues (base, screenshot & failure output).
Zooming in on the base and the screenshot image shows how little difference there is on the fonts, but enough for the test to fail.
image_comparison.zip
As for the config that we use, it is simply the following snippet:
compare(base, comp, diff, { threshold: 0.3, antialiasing: true })
What about creating a Cypress plugin to facilitate the use of odiff within Cypress?
Please make the app assume nul for the diff output if nothing is given instead
Line 30 in 6268409
I'm confused why this line is like this. I'd assume the threshold (from 0 to 1) only needs to be multiplied once?
Hey! I saw the README says that the formula is awaiting homebrew approval, but I was unable to find any open PRs in homebrew-core. Is it somewhere else perhaps, like a tap?
Hello,
I saw your sample images use Cypress screenshots. So, do you have by any chance a sample code with Cypress with necessary configurations?
Thanks
Jeff
For the npm package, the fourth options
arg is required for compare()
but isn't documented. When calling compare
with this code:
const { match, reason } = await compare("path/to/first/image.png",
"path/to/second/image.png",
"path/to/diff.png");
I get this error:
(node:87053) UnhandledPromiseRejectionWarning: TypeError: Cannot read property '__binaryPath' of undefined
at /home/raven/Documents/jobs/deviate-labs/repos/Deviate-Site-Tester/node_modules/odiff-bin/odiff.js:86:32
at new Promise (<anonymous>)
at compare (/home/raven/Documents/jobs/deviate-labs/repos/Deviate-Site-Tester/node_modules/odiff-bin/odiff.js:83:10)
at tmp (file:///home/raven/Documents/jobs/deviate-labs/repos/Deviate-Site-Tester/test.js:3:35)
at file:///home/raven/Documents/jobs/deviate-labs/repos/Deviate-Site-Tester/test.js:7:1
at ModuleJob.run (internal/modules/esm/module_job.js:152:23)
at async Loader.import (internal/modules/esm/loader.js:166:24)
at async Object.loadESM (internal/process/esm_loader.js:68:5)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:87053) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
(node:87053) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
The fourth argument should be documented or made optional. Note that the fourth arg can be "" and it works fine. This code doesn't error out:
const { match, reason } = await compare("path/to/first/image.png",
"path/to/second/image.png",
"path/to/diff.png",
"");
const a = [
{},
{},
{
"b": null,
"i": 2587.884,
"j": 89.2944,
"k": 1254.2556,
"l": 1880.97
},
{
"b": null,
"i": 386.11559999999986,
"j": 1102.9512,
"k": 1252.6019999999999,
"l": 814.398
},
{
"b": null,
"i": 386.11559999999986,
"j": 150.4776,
"k": 1252.6019999999999,
"l": 814.398
},
{}
]
const b = [
{},
{},
{
"b": "603c8f2d-db93-45ec-bea3-f6cd2f6be5b7",
"i": 2587.825865625,
"j": 89.2944,
"k": 1254.37186875,
"l": 1880.97
},
{
"b": "3c1a45a6-b776-4a54-852a-6a4103105ddc",
"i": 386.11559999999986,
"j": 570.9921868791004,
"k": 1252.6019999999999,
"l": 1878.3160262417994
},
{
"b": "5f3f02f7-e0e4-4a01-8126-73e33845f6cd",
"i": 386.11559999999986,
"j": -381.4814131208996,
"k": 1252.6019999999999,
"l": 1878.3160262417994
},
{}
]
console.log(odiff(a, b))
The result is
[{
"type": "rm",
"path": [],
"index": 0,
"num": 3,
"vals": [{}, {}, {
"b": null,
"i": 2587.884,
"j": 89.2944,
"k": 1254.2556,
"l": 1880.97
}]
}, {
"type": "add",
"path": [],
"index": 2,
"vals": [{
"b": "603c8f2d-db93-45ec-bea3-f6cd2f6be5b7",
"i": 2587.825865625,
"j": 89.2944,
"k": 1254.37186875,
"l": 1880.97
}, {
"b": "3c1a45a6-b776-4a54-852a-6a4103105ddc",
"i": 386.11559999999986,
"j": 570.9921868791004,
"k": 1252.6019999999999,
"l": 1878.3160262417994
}, {
"b": "5f3f02f7-e0e4-4a01-8126-73e33845f6cd",
"i": 386.11559999999986,
"j": -381.4814131208996,
"k": 1252.6019999999999,
"l": 1878.3160262417994
}]
}]
I recently investigated why the size of the package is that big and found out, that we include a lot of unnecessary stuff.
It also seems like esy includes the RunTests.exe in the release build.
Things that can be removed from the package:
I can't find any demonstration code how to use this lib anywhere. Doesn't help that both NPM & Oracle have packages of the same name....
TIA :)
Can't install odiff-bin
using pnpm: Esy prefix path is too deep in the filesystem, Esy won't be able to relocate artefacts
Installing using npm works fine though.
Stderr:
$ pnpm i odiff-bin
Packages: +1
+
Downloading registry.npmjs.org/odiff-bin/2.2.0: 12.3 MB/12.3 MB, done
Packages are hard linked from the content-addressable store to the virtual store.
Content-addressable store is at: /Users/privatenumber/.pnpm-store/v3
Virtual store is at: node_modules/.pnpm
Progress: resolved 1, reused 0, downloaded 1, added 1, done
node_modules/.pnpm/[email protected]/node_modules/odiff-bin: Running postinstall script, failed in 166ms
.../node_modules/odiff-bin postinstall$ node ./postinstall.js
│ error: Esy prefix path is too deep in the filesystem, Esy won't be able to relocate artefacts
└─ Failed in 166ms
ERROR Command failed with exit code 1.
cd
into itnpm init
pnpm i odiff-bin
(If you don't have pnpm installed, you can use npx: npx pnpm i odiff-bin
)macOS Big Sur v11.3.1
$ node -v
v14.16.1
$ pnpm -v
6.2.1
In order to ignore noise from anti-aliasing would be useful to implement it's support
example from pixelmatch
https://github.com/mapbox/pixelmatch/blob/2b03b635cffb9525bcefee4cc7329f98e375cff5/index.js#L93
paper:
https://www.researchgate.net/publication/234126755_Anti-aliased_Pixel_and_Intensity_Slope_Detector
Can you please make a Windows build? I'm having problems using the latest available which is 2.4.2 because I get
odiff: internal error, uncaught exception:
Failure("This format is not supported: .jpg")
And installing through npm doesn't work either, it outputs a weird unix error by just using --help
.
docker image node:12.18.4-alpine
odiff-bin 2.4.1
api_1 | [Nest] 25 - 07/15/2021, 3:59:59 PM Object:
api_1 | {}
api_1 | +31481ms
api_1 | Error
api_1 | at ChildProcess.<anonymous> (/node_modules/odiff-bin/odiff.js:134:13)
api_1 | at ChildProcess.emit (events.js:327:22)
api_1 | at maybeClose (internal/child_process.js:1021:16)
api_1 | at Socket.<anonymous> (internal/child_process.js:443:11)
api_1 | at Socket.emit (events.js:315:20)
api_1 | at Pipe.<anonymous> (net.js:674:12)
Hello, we are looking to sanity check the post-install scripts and binaries — we are wanting to try out Lost Pixel which uses odiff-bin.
They specify version 2.6.1
which exists on npm, but not here in this project apparently.
I've diffed the release tars via npm pack [email protected]
/ npm pack [email protected]
and the only changes are the version numbers in the package.json and the platform binary files (darwin, linux, windows-x64)
@dmtrKovalenko any chance you have information on the 2.6.1 release please?
Thanks
I've been using this with lost-pixel, and it gives me this error sometimes when I deploy to vercel and it uses the existing node_modules folder when reinstalling dependencies:
[14:52:43.956] [4/4] Building fresh packages...
[14:52:44.436] error /vercel/path0/node_modules/odiff-bin: Command failed.
[14:52:44.436] Exit code: 1
[14:52:44.437] Command: node ./postinstall.js
[14:52:44.437] Arguments:
[14:52:44.437] Directory: /vercel/path0/node_modules/odiff-bin
[14:52:44.437] Output:
[14:52:44.437] Could not create _export folder
[14:52:44.438] error: Error: EEXIST: file already exists, mkdir '/vercel/path0/node_modules/odiff-bin/3'
[14:52:44.439] info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
[14:52:52.090] Error: Command "yarn install" exited with 1
After performing npm install odiff-bin
without errors, the library cannot be imported:
Error: Cannot find module 'odiff-bin'
Require stack:
- ~/dev/project-dir/src/project.js
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:831:15)
at Function.Module._load (internal/modules/cjs/loader.js:687:27)
at Module.require (internal/modules/cjs/loader.js:903:19)
at require (internal/modules/cjs/helpers.js:74:18)
at Object.<anonymous> (~/dev/project-dir/src/project.js:1:21)
at Module._compile (internal/modules/cjs/loader.js:1015:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1035:10)
at Module.load (internal/modules/cjs/loader.js:879:32)
at Function.Module._load (internal/modules/cjs/loader.js:724:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12) {
code: 'MODULE_NOT_FOUND',
Attempting to run the binary directly from node_modules
reveals the following error:
~/dev/project-dir/node_modules/odiff-bin/3_________________/i/odiff-b684a0b4/bin/ODiffBin: error while loading shared libraries: libpng12.so.0: cannot open shared object file: No such file or directory
I notice the windows instructions mention that libpng
needs to be separately installed, is the same true on Linux? There doesn't appear to be a great candidate for a package in the standard Ubuntu repositories that will fix this missing dependency, is there something I'm missing?
Thanks very much.
Error: odiff: internal error, uncaught exception:
Failure("Can not write diff output. fopen error: Read-only file system")
I have a huge database of photos and am trying to compare ones of the same name to discard duplicates. Some duplicates have a different orientation flag in the EXIF data, while others have already been rotated (I probably used some jpeg optimization software on them in the past which transformed for the orientation). When comparing both images that appear the same way in image viewers, a huge difference is reported because one stores the pixels in a horizontal sequence and the other in a vertical sequence.
odiff should apply the orientation flag when loading images and transform the data accordingly. I could preprocess all images that have non standard orientation, but that requires a recompression and potential loss of quality.
Seems like a trivial thing to implement and would avoid mismatches for the unaware.
const { compare } = require("odiff-bin");
const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
const actual = (req.query.actual || (req.body && req.body.actual));
const expected = (req.query.expected || (req.body && req.body.expected));
if (actual && expected) {
try {
temp.track();
const actualPath = temp.path({ suffix: '.png' });
await downloadFileFromUrl(actual, actualPath);
const expectedPath = temp.path({ suffix: '.png' });
await downloadFileFromUrl(expected, expectedPath);
const { match, reason, diffPercentage } = await compare(
actualPath,
expectedPath
);
context.log(`Compare screenshots result: equal=${match}, reason="${reason}", diffPercentage=${diffPercentage}`)
context.res = {
body: {
equal: match,
reason,
diff: diffPercentage
}
};
}
catch (e) {
context.log(`Error occured while comparing screenshots: ${e.message}`, e);
}
finally {
const cleanupResult = await temp.cleanup();
context.log(`Cleaning up: files[${cleanupResult.files}], dirs[${cleanupResult.dirs}]`);
}
}
};
Error:
Error occured while comparing screenshots: Error at ChildProcess. (C:\home\site\wwwroot\node_modules\odiff-bin\odiff.js:134:13) at ChildProcess.emit (events.js:327:22) at maybeClose (internal/child_process.js:1048:16) at Socket. (internal/child_process.js:439:11) at Socket.emit (events.js:315:20) at Pipe. (net.js:673:12)
Any idea how to fix it?
Had a quick look at this, and it appears the tool is iterating over x-coordinates in the outer loop.
If your image library's memory layout is anything like most others out there, this isn't the most CPU/memory friendly way to go about it.
Hey. Thank you for the package. It's a great thing and an oportunity to reduce time to compare images.
Could you please add handling an error when no file found in the baseline directory?
For now I get UnhandledPromiseRejectionWarning, but I would be happy to get it via the result object. Something like this.
result: { match: false, reason: 'ENOENT: no such file or directory', details: filepath }
Right now the peerDependencies lists
"peerDependencies": {
"cypress": "10.0.3"
}
so there is a dependency warning if you are using a newer major version of cypress 10.7.0
I would propose changing it to ^n if there are no issues.
Awesome tool - thanks so much!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.