├── .dockerignore ├── .gitignore ├── output └── .gitignore ├── .github ├── FUNDING.yml └── workflows │ └── test.yml ├── samples ├── lenna.png ├── lenna-diff.png └── lenna-edit.png ├── tsconfig.json ├── docker-compose.yml ├── tsconfig.d.json ├── Dockerfile ├── LICENSE.txt ├── index.d.ts ├── package.json ├── README.md ├── index.js └── index.test.js /.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /output/.gitignore: -------------------------------------------------------------------------------- 1 | *.png 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [blueimp] 2 | -------------------------------------------------------------------------------- /samples/lenna.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blueimp/ffmpeg-image-diff/HEAD/samples/lenna.png -------------------------------------------------------------------------------- /samples/lenna-diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blueimp/ffmpeg-image-diff/HEAD/samples/lenna-diff.png -------------------------------------------------------------------------------- /samples/lenna-edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blueimp/ffmpeg-image-diff/HEAD/samples/lenna-edit.png -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "checkJs": true, 5 | "noEmit": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | services: 3 | test: 4 | build: . 5 | command: index.test.js 6 | read_only: true 7 | volumes: 8 | - .:/app:ro 9 | - ./output:/app/output 10 | -------------------------------------------------------------------------------- /tsconfig.d.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "compilerOptions": { 4 | "noEmit": false, 5 | "declaration": true, 6 | "emitDeclarationOnly": true 7 | }, 8 | "include": ["index.js"] 9 | } 10 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: actions/setup-node@v2 11 | with: 12 | node-version: 16 13 | - run: chmod -R 777 output 14 | - run: docker-compose build 15 | - run: npm install 16 | - run: npm test 17 | - if: always() 18 | uses: actions/upload-artifact@v2 19 | with: 20 | name: output 21 | path: output 22 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.14 2 | 3 | RUN apk --no-cache add \ 4 | tini \ 5 | nodejs \ 6 | npm \ 7 | ffmpeg \ 8 | && npm install -g \ 9 | npm@latest \ 10 | mocha@9 \ 11 | # Clean up obsolete files: 12 | && rm -rf \ 13 | /tmp/* \ 14 | /root/.npm 15 | 16 | # Avoid permission issues with host mounts by assigning a user/group with 17 | # uid/gid 1000 (usually the ID of the first user account on GNU/Linux): 18 | RUN adduser -D -u 1000 mocha 19 | 20 | USER mocha 21 | 22 | WORKDIR /app 23 | 24 | ENTRYPOINT ["tini", "-g", "--", "mocha"] 25 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright © 2016 Sebastian Tschan, https://blueimp.net 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | export = imageDiff; 2 | /** 3 | * Compares two images, creates diff img and returns differences as SSIM stats. 4 | * 5 | * @param {string} refImg File path to reference image 6 | * @param {string} cmpImg File path to comparison image 7 | * @param {string} [outImg] File path to output image 8 | * @param {Options} [options] Image diffing options 9 | * @returns {Promise} Resolves with the image comparison result 10 | */ 11 | declare function imageDiff(refImg: string, cmpImg: string, outImg?: string, options?: Options): Promise; 12 | declare namespace imageDiff { 13 | export { Options, Result }; 14 | } 15 | /** 16 | * Image diffing options 17 | */ 18 | type Options = { 19 | /** 20 | * Set to `false` to disable SSIM calculation 21 | */ 22 | ssim?: boolean; 23 | /** 24 | * Threshold to identify image differences 25 | */ 26 | similarity?: number; 27 | /** 28 | * Blend percentage for the differential pixels 29 | */ 30 | blend?: number; 31 | /** 32 | * Opacity of the reference image as backdrop 33 | */ 34 | opacity?: number; 35 | /** 36 | * Color balance of the differential pixels 37 | */ 38 | color?: string; 39 | }; 40 | type Result = { 41 | /** 42 | * Red color differences 43 | */ 44 | R?: number; 45 | /** 46 | * Green color differences 47 | */ 48 | G?: number; 49 | /** 50 | * blue color differences 51 | */ 52 | B?: number; 53 | /** 54 | * All color differences 55 | */ 56 | All?: number; 57 | }; 58 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ffmpeg-image-diff", 3 | "version": "1.16.0", 4 | "title": "FFmpeg Image Diff", 5 | "description": "An image diffing library using FFmpeg. Creates an image showing perceptual differences and returns SSIM data.", 6 | "keywords": [ 7 | "ffmpeg", 8 | "image", 9 | "diff", 10 | "ssim" 11 | ], 12 | "homepage": "https://github.com/blueimp/ffmpeg-image-diff", 13 | "author": { 14 | "name": "Sebastian Tschan", 15 | "url": "https://blueimp.net" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git://github.com/blueimp/ffmpeg-image-diff.git" 20 | }, 21 | "license": "MIT", 22 | "engines": { 23 | "node": ">=10.0.0" 24 | }, 25 | "devDependencies": { 26 | "@types/mocha": "9", 27 | "@types/node": "16", 28 | "eslint": "7", 29 | "eslint-config-blueimp": "2", 30 | "eslint-config-prettier": "8", 31 | "eslint-plugin-jsdoc": "36", 32 | "eslint-plugin-node": "11", 33 | "eslint-plugin-prettier": "4", 34 | "prettier": "2", 35 | "typescript": "4" 36 | }, 37 | "eslintConfig": { 38 | "extends": [ 39 | "blueimp", 40 | "plugin:jsdoc/recommended", 41 | "plugin:node/recommended", 42 | "plugin:prettier/recommended" 43 | ] 44 | }, 45 | "prettier": { 46 | "arrowParens": "avoid", 47 | "proseWrap": "always", 48 | "semi": false, 49 | "singleQuote": true, 50 | "trailingComma": "none" 51 | }, 52 | "scripts": { 53 | "pretest": "eslint . && tsc", 54 | "test": "docker-compose run --rm test", 55 | "posttest": "docker-compose down", 56 | "build": "tsc -p tsconfig.d.json", 57 | "preversion": "npm test", 58 | "version": "npm run build && git add -A index.d.ts", 59 | "postversion": "git push --tags origin HEAD && npm publish" 60 | }, 61 | "files": [ 62 | "index.d.ts", 63 | "index.js" 64 | ], 65 | "main": "index.js" 66 | } 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FFmpeg Image Diff 2 | 3 | A [NodeJS](https://nodejs.org/) image diffing library using 4 | [FFmpeg](https://www.ffmpeg.org/). 5 | Creates an image showing perceptual differences and returns 6 | [SSIM](https://en.wikipedia.org/wiki/Structural_similarity) data. 7 | 8 | ## Contents 9 | 10 | - [Requirements](#requirements) 11 | - [Install](#install) 12 | - [Usage](#usage) 13 | - [Options](#options) 14 | - [ssim](#ssim) 15 | - [similarity](#similarity) 16 | - [blend](#blend) 17 | - [opacity](#opacity) 18 | - [color](#color) 19 | - [Samples](#samples) 20 | - [Reference image](#reference-image) 21 | - [Comparison image](#comparison-image) 22 | - [Output image](#output-image) 23 | - [Testing](#testing) 24 | - [License](#license) 25 | - [Author](#author) 26 | 27 | ## Requirements 28 | 29 | This is a thin wrapper around [FFmpeg](https://www.ffmpeg.org/) and has no other 30 | dependencies. 31 | 32 | ## Install 33 | 34 | ```sh 35 | npm install ffmpeg-image-diff 36 | ``` 37 | 38 | ## Usage 39 | 40 | Displaying [SSIM](https://en.wikipedia.org/wiki/Structural_similarity) data 41 | only: 42 | 43 | ```js 44 | const imgDiff = require('ffmpeg-image-diff') 45 | 46 | imgDiff( 47 | referenceImage, // e.g. 'test/lenna.png' 48 | comparisonImage // e.g. 'test/lenna-edit.png' 49 | ) 50 | .then(ssim => { 51 | // Sample output: { R: 0.990149, G: 0.991289, B: 0.990579, All: 0.990672 } 52 | console.log(ssim) 53 | }) 54 | .catch(error => { 55 | console.error(error) 56 | }) 57 | ``` 58 | 59 | Creating a differential image with default options: 60 | 61 | ```js 62 | const imgDiff = require('ffmpeg-image-diff') 63 | 64 | imgDiff( 65 | referenceImage, // e.g. 'test/lenna.png' 66 | comparisonImage, // e.g. 'test/lenna-edit.png' 67 | outputImage, // e.g. 'test/out.png', overwrites an existing file 68 | { 69 | ssim: true, // true or false 70 | similarity: 0.01, // 1.0 - 0.01 71 | blend: 1.0, // 1.0 - 0.0 72 | opacity: 0.1, // 1.0 - 0.0 73 | color: 'magenta' // magenta, yellow, cyan, red green, blue or '' 74 | } 75 | ) 76 | .then(ssim => { 77 | // Sample output: { R: 0.990149, G: 0.991289, B: 0.990579, All: 0.990672 } 78 | console.log(ssim) 79 | }) 80 | .catch(error => { 81 | console.error(error) 82 | }) 83 | ``` 84 | 85 | ## Options 86 | 87 | ### ssim 88 | 89 | If set to `false`, disables 90 | [SSIM](https://en.wikipedia.org/wiki/Structural_similarity) calculation. 91 | _Default:_ `true` 92 | 93 | ### similarity 94 | 95 | Defines the threshold to identify image differences. 96 | `0.01` matches slight differences, while `1.0` only matches stark contrast. 97 | _Range:_ `1.0 - 0.01` 98 | _Default:_ `0.01` 99 | 100 | ### blend 101 | 102 | Blend percentage for the differential pixels. 103 | Higher values result in semi-transparent pixels, with a higher transparency the 104 | more similar the pixels color is to the original color. 105 | _Range:_ `1.0 - 0.0` 106 | _Default:_ `1.0` 107 | 108 | ### opacity 109 | 110 | Opacity of the reference image as backdrop for the differential image. 111 | Higher values result in a more opaque background image. 112 | _Range:_ `1.0 - 0.0` 113 | _Default:_ `0.1` 114 | 115 | ### color 116 | 117 | The color balance of the differential pixels. 118 | An empty string displays the default differential pixels. 119 | _Set:_ `['magenta', 'yellow', 'cyan', 'red', 'green', 'blue', '']` 120 | _Default:_ `'magenta'` 121 | 122 | ## Samples 123 | 124 | ### Reference image 125 | 126 | ![Lenna](samples/lenna.png) 127 | 128 | ### Comparison image 129 | 130 | ![Lenna Edit](samples/lenna-edit.png) 131 | 132 | ### Output image 133 | 134 | ![Lenna Diff](samples/lenna-diff.png) 135 | 136 | ## Testing 137 | 138 | 1. Start [Docker](https://docs.docker.com/). 139 | 2. Install development dependencies: 140 | ```sh 141 | npm install 142 | ``` 143 | 3. Run the tests: 144 | ```sh 145 | npm test 146 | ``` 147 | 148 | ## License 149 | 150 | Released under the [MIT license](https://opensource.org/licenses/MIT). 151 | 152 | ## Author 153 | 154 | [Sebastian Tschan](https://blueimp.net/) 155 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * An image diffing library using FFmpeg. 3 | * Creates an image showing perceptual differences and returns SSIM data. 4 | * 5 | * For documentation on the image filters used, please see 6 | * https://ffmpeg.org/ffmpeg-filters.html 7 | * 8 | * On the definition of SSIM, please see 9 | * https://en.wikipedia.org/wiki/Structural_similarity 10 | * 11 | * Copyright 2016, Sebastian Tschan 12 | * https://blueimp.net 13 | * 14 | * Licensed under the MIT license: 15 | * https://opensource.org/licenses/MIT 16 | */ 17 | 18 | 'use strict' 19 | 20 | /** 21 | * @typedef {object} Options Image diffing options 22 | * @property {boolean} [ssim=true] Set to `false` to disable SSIM calculation 23 | * @property {number} [similarity=0.01] Threshold to identify image differences 24 | * @property {number} [blend=1.0] Blend percentage for the differential pixels 25 | * @property {number} [opacity=0.1] Opacity of the reference image as backdrop 26 | * @property {string} [color=magenta] Color balance of the differential pixels 27 | */ 28 | 29 | /** 30 | * @typedef {object} Result 31 | * @property {number} [R] Red color differences 32 | * @property {number} [G] Green color differences 33 | * @property {number} [B] blue color differences 34 | * @property {number} [All] All color differences 35 | */ 36 | 37 | const execFile = require('util').promisify(require('child_process').execFile) 38 | 39 | /** 40 | * Compares two images, creates diff and returns differences as SSIM stats. 41 | * 42 | * @param {string} refImg File path to reference image 43 | * @param {string} cmpImg File path to comparison image 44 | * @param {Array} args ffmpeg arguments 45 | * @returns {Promise} Resolves with the image comparison result 46 | */ 47 | function ffmpeg(refImg, cmpImg, args) { 48 | return execFile( 49 | 'ffmpeg', 50 | ['-loglevel', 'error', '-i', refImg, '-i', cmpImg].concat(args) 51 | ).then(function (result) { 52 | // SSIM log output has the following format: 53 | // n:1 R:x.xxxxxx G:x.xxxxxx B:x.xxxxxx All:x.xxxxxx (xx.xxxxxx) 54 | // We only keep the R, G, B and All values and turn them into an object: 55 | return result.stdout 56 | .split(' ') 57 | .slice(1, -1) 58 | .reduce(function (obj, val) { 59 | const tupel = val.split(':') 60 | obj[tupel[0]] = parseFloat(tupel[1]) 61 | return obj 62 | }, {}) 63 | }) 64 | } 65 | 66 | /** 67 | * Compares two images, creates diff img and returns differences as SSIM stats. 68 | * 69 | * @param {string} refImg File path to reference image 70 | * @param {string} cmpImg File path to comparison image 71 | * @param {string} [outImg] File path to output image 72 | * @param {Options} [options] Image diffing options 73 | * @returns {Promise} Resolves with the image comparison result 74 | */ 75 | function imageDiff(refImg, cmpImg, outImg, options) { 76 | if (!outImg) { 77 | // Resolve with the SSIM stats without creating a differential image: 78 | return ffmpeg(refImg, cmpImg, [ 79 | '-filter_complex', 80 | 'ssim=stats_file=-', 81 | '-f', 82 | 'null', 83 | '-' 84 | ]) 85 | } 86 | const opts = Object.assign( 87 | { 88 | ssim: true, // true or false 89 | similarity: 0.01, // 1.0 - 0.01 90 | blend: 1.0, // 1.0 - 0.0 91 | opacity: 0.1, // 1.0 - 0.0 92 | color: 'magenta' // magenta, yellow, cyan, red green, blue or '' 93 | }, 94 | options 95 | ) 96 | const ssim = opts.ssim ? 'ssim=stats_file=-[ssim];[ssim][1]' : '' 97 | const colorkey = 98 | 'format=rgba,colorkey=white' + 99 | `:similarity=${opts.similarity}:blend=${opts.blend}` 100 | let colorbalance = 'colorbalance=' 101 | switch (opts.color) { 102 | case 'magenta': 103 | colorbalance += `rs=1:gs=-1:bs=1:rm=1:gm=-1:bm=1:rh=1:gh=-1:bh=1` 104 | break 105 | case 'yellow': 106 | colorbalance += `rs=1:gs=1:bs=-1:rm=1:gm=1:bm=-1:rh=1:gh=1:bh=-1` 107 | break 108 | case 'cyan': 109 | colorbalance += `rs=-1:gs=1:bs=1:rm=-1:gm=1:bm=1:rh=-1:gh=1:bh=1` 110 | break 111 | case 'red': 112 | colorbalance += `rs=1:gs=-1:bs=-1:rm=1:gm=-1:bm=-1:rh=1:gh=-1:bh=-1` 113 | break 114 | case 'green': 115 | colorbalance += `rs=-1:gs=1:bs=-1:rm=-1:gm=1:bm=-1:rh=-1:gh=1:bh=-1` 116 | break 117 | case 'blue': 118 | colorbalance += `rs=-1:gs=-1:bs=1:rm=-1:gm=-1:bm=1:rh=-1:gh=-1:bh=1` 119 | break 120 | default: 121 | colorbalance += opts.color 122 | } 123 | // Create a differential image with transparent background. 124 | // The differences are highlighted with the given colorbalance: 125 | const diff = `blend=all_mode=phoenix,${colorkey},${colorbalance}[diff];` 126 | // Use the reference file as background with the given opacity: 127 | const bg = 128 | opts.opacity < 1 129 | ? `format=rgba,colorchannelmixer=aa=${opts.opacity}[bg];[bg]` 130 | : '' 131 | // Overlay the background with the diff: 132 | const overlay = `[0]${bg}[diff]overlay=format=rgb` 133 | // Create a differential image with the given arguments: 134 | return ffmpeg(refImg, cmpImg, [ 135 | '-filter_complex', 136 | `${ssim}${diff}${overlay}`, 137 | '-y', 138 | outImg 139 | ]) 140 | } 141 | 142 | module.exports = imageDiff 143 | -------------------------------------------------------------------------------- /index.test.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /* global describe, it */ 4 | 5 | /** @type {object} */ 6 | const assert = require('assert') 7 | const imgDiff = require('.') 8 | 9 | const referenceImage = 'samples/lenna.png' 10 | const comparisonImage = 'samples/lenna-edit.png' 11 | 12 | describe('image diff', function () { 13 | this.slow(300) 14 | 15 | it('no output image', async function () { 16 | this.slow(150) 17 | const result = await imgDiff(referenceImage, comparisonImage) 18 | assert.strictEqual(typeof result.R, 'number') 19 | assert.strictEqual(typeof result.G, 'number') 20 | assert.strictEqual(typeof result.B, 'number') 21 | assert.strictEqual(typeof result.All, 'number') 22 | }) 23 | 24 | it('default', async function () { 25 | const result = await imgDiff( 26 | referenceImage, 27 | comparisonImage, 28 | 'output/default.png' 29 | ) 30 | assert.strictEqual(typeof result.R, 'number') 31 | assert.strictEqual(typeof result.G, 'number') 32 | assert.strictEqual(typeof result.B, 'number') 33 | assert.strictEqual(typeof result.All, 'number') 34 | }) 35 | 36 | it('color yellow', async function () { 37 | const result = await imgDiff( 38 | referenceImage, 39 | comparisonImage, 40 | 'output/color-yellow.png', 41 | { color: 'yellow' } 42 | ) 43 | assert.strictEqual(typeof result.R, 'number') 44 | assert.strictEqual(typeof result.G, 'number') 45 | assert.strictEqual(typeof result.B, 'number') 46 | assert.strictEqual(typeof result.All, 'number') 47 | }) 48 | 49 | it('color cyan', async function () { 50 | const result = await imgDiff( 51 | referenceImage, 52 | comparisonImage, 53 | 'output/color-cyan.png', 54 | { color: 'cyan' } 55 | ) 56 | assert.strictEqual(typeof result.R, 'number') 57 | assert.strictEqual(typeof result.G, 'number') 58 | assert.strictEqual(typeof result.B, 'number') 59 | assert.strictEqual(typeof result.All, 'number') 60 | }) 61 | 62 | it('color red', async function () { 63 | const result = await imgDiff( 64 | referenceImage, 65 | comparisonImage, 66 | 'output/color-red.png', 67 | { color: 'red' } 68 | ) 69 | assert.strictEqual(typeof result.R, 'number') 70 | assert.strictEqual(typeof result.G, 'number') 71 | assert.strictEqual(typeof result.B, 'number') 72 | assert.strictEqual(typeof result.All, 'number') 73 | }) 74 | 75 | it('color green', async function () { 76 | const result = await imgDiff( 77 | referenceImage, 78 | comparisonImage, 79 | 'output/color-green.png', 80 | { color: 'green' } 81 | ) 82 | assert.strictEqual(typeof result.R, 'number') 83 | assert.strictEqual(typeof result.G, 'number') 84 | assert.strictEqual(typeof result.B, 'number') 85 | assert.strictEqual(typeof result.All, 'number') 86 | }) 87 | 88 | it('color blue', async function () { 89 | const result = await imgDiff( 90 | referenceImage, 91 | comparisonImage, 92 | 'output/color-blue.png', 93 | { color: 'blue' } 94 | ) 95 | assert.strictEqual(typeof result.R, 'number') 96 | assert.strictEqual(typeof result.G, 'number') 97 | assert.strictEqual(typeof result.B, 'number') 98 | assert.strictEqual(typeof result.All, 'number') 99 | }) 100 | 101 | it('color empty', async function () { 102 | const result = await imgDiff( 103 | referenceImage, 104 | comparisonImage, 105 | 'output/color-empty.png', 106 | { color: '' } 107 | ) 108 | assert.strictEqual(typeof result.R, 'number') 109 | assert.strictEqual(typeof result.G, 'number') 110 | assert.strictEqual(typeof result.B, 'number') 111 | assert.strictEqual(typeof result.All, 'number') 112 | }) 113 | 114 | it('similarity 1', async function () { 115 | const result = await imgDiff( 116 | referenceImage, 117 | comparisonImage, 118 | 'output/similarity-1.png', 119 | { similarity: 1 } 120 | ) 121 | assert.strictEqual(typeof result.R, 'number') 122 | assert.strictEqual(typeof result.G, 'number') 123 | assert.strictEqual(typeof result.B, 'number') 124 | assert.strictEqual(typeof result.All, 'number') 125 | }) 126 | 127 | it('blend 0', async function () { 128 | const result = await imgDiff( 129 | referenceImage, 130 | comparisonImage, 131 | 'output/blend-0.png', 132 | { blend: 0 } 133 | ) 134 | assert.strictEqual(typeof result.R, 'number') 135 | assert.strictEqual(typeof result.G, 'number') 136 | assert.strictEqual(typeof result.B, 'number') 137 | assert.strictEqual(typeof result.All, 'number') 138 | }) 139 | 140 | it('opacity 0', async function () { 141 | const result = await imgDiff( 142 | referenceImage, 143 | comparisonImage, 144 | 'output/opacity-0.png', 145 | { opacity: 0 } 146 | ) 147 | assert.strictEqual(typeof result.R, 'number') 148 | assert.strictEqual(typeof result.G, 'number') 149 | assert.strictEqual(typeof result.B, 'number') 150 | assert.strictEqual(typeof result.All, 'number') 151 | }) 152 | 153 | it('opacity 1', async function () { 154 | const result = await imgDiff( 155 | referenceImage, 156 | comparisonImage, 157 | 'output/opacity-1.png', 158 | { opacity: 1 } 159 | ) 160 | assert.strictEqual(typeof result.R, 'number') 161 | assert.strictEqual(typeof result.G, 'number') 162 | assert.strictEqual(typeof result.B, 'number') 163 | assert.strictEqual(typeof result.All, 'number') 164 | }) 165 | 166 | it('ssim false', async function () { 167 | const result = await imgDiff( 168 | referenceImage, 169 | comparisonImage, 170 | 'output/ssim-false.png', 171 | { ssim: false } 172 | ) 173 | assert.strictEqual(result.constructor, Object) 174 | assert.strictEqual(Object.entries(result).length, 0) 175 | }) 176 | }) 177 | --------------------------------------------------------------------------------