Comparing version 1.1.0 to 1.2.0
588
index.js
'use strict'; | ||
const { Transform } = require('stream'); | ||
const { Transform } = require('node:stream'); | ||
const { performance } = require('node:perf_hooks'); | ||
const PP = require('polygon-points'); | ||
@@ -13,27 +15,20 @@ | ||
* @param [options] {Object} | ||
* @param [options.debug=false] {Boolean} - If true, debug info will be logged to console | ||
* @param [options.difference=5] {Number} - Pixel difference value 1 to 255 | ||
* @param [options.difference=5] {Number} - Pixel difference value, int 1 to 255 | ||
* @param [options.percent=5] {Number} - Percent of pixels or blobs that exceed difference value, float 0.0 to 100.0 | ||
* @param [options.response=percent] {String} - Accepted values: percent or bounds or blobs | ||
* @param [options.draw=false] {Boolean} - If true and response is 'bounds' or 'blobs', return a pixel buffer with drawn bounding box | ||
* @param [options.regions] {Array} - Array of region objects | ||
* @param options.regions[i].name {String} - Name of region | ||
* @param [options.regions[i].difference=options.difference] {Number} - Difference value for region | ||
* @param [options.regions[i].difference=options.difference] {Number} - Difference value for region, int 1 to 255 | ||
* @param [options.regions[i].percent=options.percent] {Number} - Percent value for region, float 0.0 to 100.0 | ||
* @param options.regions[i].polygon {Array} - Array of x y coordinates [{x:0,y:0},{x:0,y:360},{x:160,y:360},{x:160,y:0}] | ||
* @param [options.mask=false] {Boolean} - Indicate if regions should be used as masks of pixels to ignore | ||
* @param [callback] {Function} - Function to be called when diff event occurs | ||
* @param [options.draw=false] {Boolean} - If true and response is 'bounds' or 'blobs', return a pixel buffer with drawn bounding box | ||
* @param [options.debug=false] {Boolean} - If true, debug object will be attached to output | ||
* @param [callback] {Function} - Function to be called when diff event occurs. Deprecated | ||
*/ | ||
constructor(options, callback) { | ||
super(options); | ||
Transform.call(this, { objectMode: true }); | ||
this.debug = PamDiff._parseOptions('debug', options); // output debug info to console. defaults to false | ||
this.response = PamDiff._parseOptions('response', options); // percent, bounds, blobs | ||
this.draw = PamDiff._parseOptions('draw', options); // return pixels with bounding box if response is bounds or blobs | ||
this.difference = PamDiff._parseOptions('difference', options); // global value, can be overridden per region | ||
this.percent = PamDiff._parseOptions('percent', options); // global value, can be overridden per region | ||
this.mask = PamDiff._parseOptions('mask', options); // should be processed before regions | ||
this.regions = PamDiff._parseOptions('regions', options); // can be zero regions, a single region, or multiple regions. if no regions, all pixels will be compared. | ||
this.callback = callback; // callback function to be called when pixel difference is detected | ||
this._parseChunk = this._parseFirstChunk; // first parsing will be reading settings and configuring internal pixel reading | ||
super({ objectMode: true }); | ||
this.config = options; // configuration for pixel change detection | ||
this.callback = callback; // callback function to be called when pixel change is detected | ||
this._parseChunk = this._parseFirstChunk; // first parsing will be used to configure pixel diff engine | ||
} | ||
@@ -43,12 +38,15 @@ | ||
* | ||
* @param option {String} | ||
* @param options {Object} | ||
* @return {*} | ||
* @private | ||
* @param obj {Object} | ||
*/ | ||
static _parseOptions(option, options) { | ||
if (options && options.hasOwnProperty(option)) { | ||
return options[option]; | ||
set config(obj) { | ||
if (obj instanceof Object) { | ||
this._difference = PamDiff._validateInt(obj.difference, 5, 1, 255); | ||
this._percent = PamDiff._validateFloat(obj.percent, 5, 0, 100); | ||
this._response = PamDiff._validateString(obj.response, ['percent', 'bounds', 'blobs']); | ||
this._regions = PamDiff._validateArray(obj.regions); | ||
this._mask = PamDiff._validateBoolean(obj.mask); | ||
this._draw = PamDiff._validateBoolean(obj.draw); | ||
this._debug = PamDiff._validateBoolean(obj.debug); | ||
this._configurePixelDiffEngine(); | ||
} | ||
return null; | ||
} | ||
@@ -58,19 +56,14 @@ | ||
* | ||
* @param number {Number} | ||
* @param def {Number} | ||
* @param low {Number} | ||
* @param high {Number} | ||
* @return {Number} | ||
* @private | ||
* @returns {Object} | ||
*/ | ||
static _validateNumber(number, def, low, high) { | ||
if (isNaN(number)) { | ||
return def; | ||
} else if (number < low) { | ||
return low; | ||
} else if (number > high) { | ||
return high; | ||
} else { | ||
return number; | ||
} | ||
get config() { | ||
return { | ||
difference: this._difference, | ||
percent: this._percent, | ||
response: this._response, | ||
regions: this._regions, | ||
mask: this._mask, | ||
draw: this._draw, | ||
debug: this._debug, | ||
}; | ||
} | ||
@@ -80,8 +73,7 @@ | ||
* | ||
* @param bool | ||
* @return {boolean} | ||
* @private | ||
* @param num {Number} | ||
*/ | ||
static _validateBoolean(bool) { | ||
return bool === true || bool === 'true' || bool === 1 || bool === '1'; | ||
set difference(num) { | ||
this._difference = PamDiff._validateInt(num, 5, 1, 255); | ||
this._configurePixelDiffEngine(); | ||
} | ||
@@ -91,12 +83,6 @@ | ||
* | ||
* @param string {String} | ||
* @param strings {Array} | ||
* @return {String} | ||
* @private | ||
* @return {Number} | ||
*/ | ||
static _validateString(string, strings) { | ||
if (strings.includes(string)) { | ||
return string; | ||
} | ||
return strings[0]; | ||
get difference() { | ||
return this._difference; | ||
} | ||
@@ -106,7 +92,17 @@ | ||
* | ||
* @param bool {Boolean} | ||
* @param num {Number} | ||
* @return {PamDiff} | ||
* @deprecated | ||
*/ | ||
set debug(bool) { | ||
this._debug = PamDiff._validateBoolean(bool); | ||
this._processRegions(); | ||
setDifference(num) { | ||
this.difference = num; | ||
return this; | ||
} | ||
/** | ||
* | ||
* @param num {Number|String} | ||
*/ | ||
set percent(num) { | ||
this._percent = PamDiff._validateFloat(num, 5, 0, 100); | ||
this._configurePixelDiffEngine(); | ||
@@ -117,6 +113,6 @@ } | ||
* | ||
* @return {Boolean} | ||
* @return {Number} | ||
*/ | ||
get debug() { | ||
return this._debug; | ||
get percent() { | ||
return this._percent; | ||
} | ||
@@ -126,7 +122,8 @@ | ||
* | ||
* @param bool {Boolean} | ||
* @param num {Number} | ||
* @return {PamDiff} | ||
* @deprecated | ||
*/ | ||
setDebug(bool) { | ||
this.debug = bool; | ||
setPercent(num) { | ||
this.percent = num; | ||
return this; | ||
@@ -137,7 +134,6 @@ } | ||
* | ||
* @param string {String} | ||
* @param str {String} | ||
*/ | ||
set response(string) { | ||
this._response = PamDiff._validateString(string, ['percent', 'bounds', 'blobs']); | ||
this._processRegions(); | ||
set response(str) { | ||
this._response = PamDiff._validateString(str, ['percent', 'bounds', 'blobs']); | ||
this._configurePixelDiffEngine(); | ||
@@ -156,7 +152,8 @@ } | ||
* | ||
* @param string {String} | ||
* @param str {String} | ||
* @return {PamDiff} | ||
* @deprecated | ||
*/ | ||
setResponse(string) { | ||
this.response = string; | ||
setResponse(str) { | ||
this.response = str; | ||
return this; | ||
@@ -167,7 +164,6 @@ } | ||
* | ||
* @param bool {Boolean} | ||
* @param arr {Array} | ||
*/ | ||
set draw(bool) { | ||
this._draw = PamDiff._validateBoolean(bool); | ||
this._processRegions(); | ||
set regions(arr) { | ||
this._regions = PamDiff._validateArray(arr); | ||
this._configurePixelDiffEngine(); | ||
@@ -178,6 +174,6 @@ } | ||
* | ||
* @return {Boolean} | ||
* @return {Array} | ||
*/ | ||
get draw() { | ||
return this._draw; | ||
get regions() { | ||
return this._regions; | ||
} | ||
@@ -187,7 +183,8 @@ | ||
* | ||
* @param bool {Boolean} | ||
* @param arr {Object[]} | ||
* @return {PamDiff} | ||
* @deprecated | ||
*/ | ||
setDraw(bool) { | ||
this.draw = bool; | ||
setRegions(arr) { | ||
this.regions = arr; | ||
return this; | ||
@@ -198,6 +195,6 @@ } | ||
* | ||
* @param number {Number} | ||
* @param bool {Boolean|String|Number} | ||
*/ | ||
set difference(number) { | ||
this._difference = PamDiff._validateNumber(parseInt(number), 5, 1, 255); | ||
set mask(bool) { | ||
this._mask = PamDiff._validateBoolean(bool); | ||
this._configurePixelDiffEngine(); | ||
@@ -208,6 +205,6 @@ } | ||
* | ||
* @return {Number} | ||
* @returns {Boolean} | ||
*/ | ||
get difference() { | ||
return this._difference; | ||
get mask() { | ||
return this._mask; | ||
} | ||
@@ -217,7 +214,8 @@ | ||
* | ||
* @param number {Number} | ||
* @return {PamDiff} | ||
* @param bool {Boolean} | ||
* @returns {PamDiff} | ||
* @deprecated | ||
*/ | ||
setDifference(number) { | ||
this.difference = number; | ||
setMask(bool) { | ||
this.mask = bool; | ||
return this; | ||
@@ -228,6 +226,6 @@ } | ||
* | ||
* @param number {Number|String} | ||
* @param bool {Boolean} | ||
*/ | ||
set percent(number) { | ||
this._percent = PamDiff._validateNumber(parseFloat(number), 5, 0, 100); | ||
set draw(bool) { | ||
this._draw = PamDiff._validateBoolean(bool); | ||
this._configurePixelDiffEngine(); | ||
@@ -238,6 +236,6 @@ } | ||
* | ||
* @return {Number} | ||
* @return {Boolean} | ||
*/ | ||
get percent() { | ||
return this._percent; | ||
get draw() { | ||
return this._draw; | ||
} | ||
@@ -247,7 +245,8 @@ | ||
* | ||
* @param number {Number} | ||
* @param bool {Boolean} | ||
* @return {PamDiff} | ||
* @deprecated | ||
*/ | ||
setPercent(number) { | ||
this.percent = number; | ||
setDraw(bool) { | ||
this.draw = bool; | ||
return this; | ||
@@ -258,17 +257,6 @@ } | ||
* | ||
* @param array {Array} | ||
* @param bool {Boolean|String|Number} | ||
*/ | ||
set regions(array) { | ||
if (!array) { | ||
delete this._regions; | ||
delete this._regionObj; | ||
delete this._maskObj; | ||
} else if (!Array.isArray(array) || array.length < 1) { | ||
throw new Error( | ||
`Regions must be an array of at least 1 region object { name: 'region1', difference: 10, percent: 1, polygon: [{x: 0, y: 0}, {x: 0, y:50}, {x: 50, y:50}, {x: 50, y: 0}] }` | ||
); | ||
} else { | ||
this._regions = array; | ||
this._processRegions(); | ||
} | ||
set debug(bool) { | ||
this._debug = PamDiff._validateBoolean(bool); | ||
this._configurePixelDiffEngine(); | ||
@@ -279,6 +267,6 @@ } | ||
* | ||
* @return {Array} | ||
* @return {Boolean} | ||
*/ | ||
get regions() { | ||
return this._regions; | ||
get debug() { | ||
return this._debug; | ||
} | ||
@@ -288,32 +276,19 @@ | ||
* | ||
* @param array {Array} | ||
* @param bool {Boolean} | ||
* @return {PamDiff} | ||
* @deprecated | ||
*/ | ||
setRegions(array) { | ||
this.regions = array; | ||
setDebug(bool) { | ||
this.debug = bool; | ||
return this; | ||
} | ||
set mask(bool) { | ||
this._mask = PamDiff._validateBoolean(bool); | ||
this._processRegions(); | ||
this._configurePixelDiffEngine(); | ||
} | ||
get mask() { | ||
return this._mask; | ||
} | ||
setMask(bool) { | ||
this.mask = bool; | ||
return this; | ||
} | ||
/** | ||
* | ||
* @param func {Function} | ||
* @deprecated | ||
*/ | ||
set callback(func) { | ||
if (!func) { | ||
delete this._callback; | ||
this._callback = undefined; | ||
} else if (typeof func === 'function' && func.length === 1) { | ||
@@ -329,2 +304,3 @@ this._callback = func; | ||
* @return {Function} | ||
* @deprecated | ||
*/ | ||
@@ -339,2 +315,3 @@ get callback() { | ||
* @return {PamDiff} | ||
* @deprecated | ||
*/ | ||
@@ -349,12 +326,21 @@ setCallback(func) { | ||
* @return {PamDiff} | ||
* @deprecated | ||
*/ | ||
resetCache() { | ||
delete this._engine; | ||
delete this._oldPix; | ||
delete this._newPix; | ||
delete this._width; | ||
delete this._height; | ||
delete this._depth; | ||
delete this._tupltype; | ||
delete this._regionObj; | ||
return this.reset(); | ||
} | ||
/** | ||
* | ||
* @return {PamDiff} | ||
*/ | ||
reset() { | ||
this.emit('reset'); | ||
this._debugInfo = undefined; | ||
this._engine = undefined; | ||
this._oldPix = undefined; | ||
this._width = undefined; | ||
this._height = undefined; | ||
this._depth = undefined; | ||
this._tupltype = undefined; | ||
this._parseChunk = this._parseFirstChunk; | ||
@@ -366,85 +352,86 @@ return this; | ||
* | ||
* @returns {Array|null} | ||
* @private | ||
*/ | ||
_processRegions() { | ||
if (!this._regions || !this._width || !this._height) { | ||
return; | ||
} | ||
const regions = []; | ||
if (this._mask === true) { | ||
// combine all regions to form a single region of flipped 0's and 1's | ||
let minX = this._width; | ||
let maxX = 0; | ||
let minY = this._height; | ||
let maxY = 0; | ||
const wxh = this._width * this._height; | ||
const maskBitset = Buffer.alloc(wxh, 1); | ||
for (const region of this._regions) { | ||
if (!region.hasOwnProperty('polygon')) { | ||
throw new Error('Region must include a polygon property'); | ||
if (this._regions) { | ||
const regions = []; | ||
if (this._mask === true) { | ||
// combine all regions to form a single region of flipped 0's and 1's | ||
let minX = this._width; | ||
let maxX = 0; | ||
let minY = this._height; | ||
let maxY = 0; | ||
const wxh = this._width * this._height; | ||
const maskBitset = Buffer.alloc(wxh, 1); | ||
for (const region of this._regions) { | ||
if (!region.hasOwnProperty('polygon')) { | ||
throw new Error('Region must include a polygon property'); | ||
} | ||
const pp = new PP(region.polygon); | ||
const bitset = pp.getBitset(this._width, this._height); | ||
if (bitset.count === 0) { | ||
throw new Error('Bitset count must be greater than 0.'); | ||
} | ||
const bitsetBuffer = bitset.buffer; | ||
for (let i = 0; i < wxh; ++i) { | ||
if (bitsetBuffer[i] === 1) { | ||
maskBitset[i] = 0; | ||
} | ||
} | ||
} | ||
const pp = new PP(region.polygon); | ||
const bitset = pp.getBitset(this._width, this._height); | ||
if (bitset.count === 0) { | ||
throw new Error('Bitset count must be greater than 0.'); | ||
} | ||
const bitsetBuffer = bitset.buffer; | ||
let maskBitsetCount = 0; | ||
for (let i = 0; i < wxh; ++i) { | ||
if (bitsetBuffer[i] === 1) { | ||
maskBitset[i] = 0; | ||
if (maskBitset[i] === 1) { | ||
const y = Math.floor(i / this._width); | ||
const x = i % this._width; | ||
minX = Math.min(minX, x); | ||
maxX = Math.max(maxX, x); | ||
minY = Math.min(minY, y); | ||
maxY = Math.max(maxY, y); | ||
maskBitsetCount++; | ||
} | ||
} | ||
} | ||
let maskBitsetCount = 0; | ||
for (let i = 0; i < wxh; ++i) { | ||
if (maskBitset[i] === 1) { | ||
const y = Math.floor(i / this._width); | ||
const x = i % this._width; | ||
minX = Math.min(minX, x); | ||
maxX = Math.max(maxX, x); | ||
minY = Math.min(minY, y); | ||
maxY = Math.max(maxY, y); | ||
maskBitsetCount++; | ||
} | ||
} | ||
if (maskBitsetCount === 0) { | ||
throw new Error('Bitset count must be greater than 0'); | ||
} | ||
regions.push({ | ||
name: 'mask', | ||
bitset: maskBitset, | ||
bitsetCount: maskBitsetCount, | ||
difference: this._difference, | ||
percent: this._percent, | ||
minX: minX, | ||
maxX: maxX, | ||
minY: minY, | ||
maxY: maxY, | ||
}); | ||
} else { | ||
for (const region of this._regions) { | ||
if (!region.hasOwnProperty('name') || !region.hasOwnProperty('polygon')) { | ||
throw new Error('Region must include a name and a polygon property'); | ||
} | ||
const pp = new PP(region.polygon); | ||
const bitset = pp.getBitset(this._width, this._height); | ||
if (bitset.count === 0) { | ||
if (maskBitsetCount === 0) { | ||
throw new Error('Bitset count must be greater than 0'); | ||
} | ||
const difference = PamDiff._validateNumber(parseInt(region.difference), this._difference, 1, 255); | ||
const percent = PamDiff._validateNumber(parseFloat(region.percent), this._percent, 0, 100); | ||
regions.push({ | ||
name: region.name, | ||
bitset: bitset.buffer, | ||
bitsetCount: bitset.count, | ||
difference: difference, | ||
percent: percent, | ||
minX: bitset.minX, | ||
maxX: bitset.maxX, | ||
minY: bitset.minY, | ||
maxY: bitset.maxY, | ||
name: 'mask', | ||
bitset: maskBitset, | ||
bitsetCount: maskBitsetCount, | ||
difference: this._difference, | ||
percent: this._percent, | ||
minX: minX, | ||
maxX: maxX, | ||
minY: minY, | ||
maxY: maxY, | ||
}); | ||
} else { | ||
for (const region of this._regions) { | ||
if (!region.hasOwnProperty('name') || !region.hasOwnProperty('polygon')) { | ||
throw new Error('Region must include a name and a polygon property'); | ||
} | ||
const pp = new PP(region.polygon); | ||
const bitset = pp.getBitset(this._width, this._height); | ||
if (bitset.count === 0) { | ||
throw new Error('Bitset count must be greater than 0'); | ||
} | ||
const difference = PamDiff._validateInt(region.difference, this._difference, 1, 255); | ||
const percent = PamDiff._validateFloat(region.percent, this._percent, 0, 100); | ||
regions.push({ | ||
name: region.name, | ||
bitset: bitset.buffer, | ||
bitsetCount: bitset.count, | ||
difference: difference, | ||
percent: percent, | ||
minX: bitset.minX, | ||
maxX: bitset.maxX, | ||
minY: bitset.minY, | ||
maxY: bitset.maxY, | ||
}); | ||
} | ||
} | ||
return regions; | ||
} | ||
this._regionObj = { length: regions.length, regions: regions }; | ||
return null; | ||
} | ||
@@ -460,31 +447,32 @@ | ||
} | ||
let engine = this._tupltype; | ||
engine += `_${this._width}_x_${this._height}`; | ||
const config = { width: this._width, height: this._height, depth: this._depth, response: this._response, sync: false }; | ||
if (this._regionObj) { | ||
engine += '_region'; | ||
// config.target = 'region'; | ||
config.regions = this._regionObj.regions; | ||
if (this._regionObj.length > 1) { | ||
engine += 's'; | ||
const regions = this._processRegions(); | ||
let name = `${this._tupltype}_${this._width}w_${this._height}h_${this._depth}d`; | ||
const config = { width: this._width, height: this._height, depth: this._depth, response: this._response }; | ||
if (regions) { | ||
if (regions.length === 1) { | ||
if (this._mask === true) { | ||
name += '_mask'; | ||
} else { | ||
name += '_region'; | ||
} | ||
} else { | ||
name += `_regions`; | ||
} | ||
config.regions = regions; | ||
} else { | ||
engine += '_all'; | ||
// config.target = 'all'; | ||
name += '_all'; | ||
config.difference = this._difference; | ||
config.percent = this._percent; | ||
} | ||
engine += `_${this._response}`; | ||
name += `_${this._response}`; | ||
if ((this._response === 'bounds' || this._response === 'blobs') && this._draw) { | ||
config.draw = this._draw; | ||
engine += '_draw'; | ||
name += '_draw'; | ||
} | ||
engine += '_async'; | ||
name += '_async'; | ||
const pixelChange = PC(config); | ||
this._engine = pixelChange.compare.bind(pixelChange); | ||
if (this._debug) { | ||
console.dir(this, { showHidden: false, depth: 0, colors: true }); | ||
this._parseChunk = this._parsePixelsDebug; | ||
this._debugEngine = engine; | ||
this._debugCount = 0; | ||
this._debugInfo = { name, count: 0 }; | ||
} else { | ||
@@ -497,23 +485,23 @@ this._parseChunk = this._parsePixels; | ||
* | ||
* @param chunk | ||
* @param chunk {Object} | ||
* @private | ||
*/ | ||
_parsePixels(chunk) { | ||
this._newPix = chunk.pixels; | ||
this._engine(this._oldPix, this._newPix, (err, data) => { | ||
const { results } = data; | ||
if (results.length) { | ||
const diff = { trigger: results, pam: chunk.pam, headers: chunk.headers, pixels: data.pixels || chunk.pixels }; | ||
if (this._callback) { | ||
this._callback(diff); | ||
} | ||
if (this._readableState.pipesCount > 0) { | ||
this.push(diff); | ||
} | ||
if (this.listenerCount('diff') > 0) { | ||
const oldPix = this._oldPix; | ||
const newPix = (this._oldPix = chunk.pixels); | ||
this._engine(oldPix, newPix, (err, data) => { | ||
if (data) { | ||
const { results, pixels } = data; | ||
const diff = { trigger: results, pam: chunk.pam, headers: chunk.headers, pixels: pixels || newPix }; | ||
this.emit('data', diff); | ||
if (results.length) { | ||
this.emit('diff', diff); | ||
if (this._callback) { | ||
this._callback(diff); | ||
} | ||
} | ||
} else { | ||
throw new Error(err); | ||
} | ||
}); | ||
this._oldPix = this._newPix; | ||
} | ||
@@ -523,26 +511,27 @@ | ||
* | ||
* @param chunk | ||
* @param chunk {Object} | ||
* @private | ||
*/ | ||
_parsePixelsDebug(chunk) { | ||
const debugCount = this._debugCount++; | ||
console.time(`${this._debugEngine}-${debugCount}`); | ||
this._newPix = chunk.pixels; | ||
this._engine(this._oldPix, this._newPix, (err, data) => { | ||
console.timeEnd(`${this._debugEngine}-${debugCount}`); | ||
const { results } = data; | ||
if (results.length) { | ||
const diff = { trigger: results, pam: chunk.pam, headers: chunk.headers, pixels: data.pixels || chunk.pixels }; | ||
if (this._callback) { | ||
this._callback(diff); | ||
} | ||
if (this._readableState.pipesCount > 0) { | ||
this.push(diff); | ||
} | ||
if (this.listenerCount('diff') > 0) { | ||
const oldPix = this._oldPix; | ||
const newPix = (this._oldPix = chunk.pixels); | ||
const count = ++this._debugInfo.count; | ||
const name = this._debugInfo.name; | ||
const start = performance.now(); | ||
this._engine(oldPix, newPix, (err, data) => { | ||
const duration = Math.round((performance.now() - start) * 1000) / 1000; | ||
if (data) { | ||
const { results, pixels } = data; | ||
const diff = { trigger: results, pam: chunk.pam, headers: chunk.headers, pixels: pixels || newPix, debug: { name, count, duration } }; | ||
this.emit('data', diff); | ||
if (results.length) { | ||
this.emit('diff', diff); | ||
if (this._callback) { | ||
this._callback(diff); | ||
} | ||
} | ||
} else { | ||
throw new Error(err); | ||
} | ||
}); | ||
this._oldPix = this._newPix; | ||
} | ||
@@ -552,13 +541,13 @@ | ||
* | ||
* @param chunk | ||
* @param chunk {Object} | ||
* @private | ||
*/ | ||
_parseFirstChunk(chunk) { | ||
this._width = parseInt(chunk.width); | ||
this._height = parseInt(chunk.height); | ||
this._depth = parseInt(chunk.depth); | ||
this._width = Number.parseInt(chunk.width); | ||
this._height = Number.parseInt(chunk.height); | ||
this._depth = Number.parseInt(chunk.depth); | ||
this._oldPix = chunk.pixels; | ||
this._tupltype = chunk.tupltype; | ||
this._processRegions(); | ||
this._configurePixelDiffEngine(); | ||
this.emit('initialized', { width: this._width, height: this._height, depth: this._depth, tupltype: this._tupltype }); | ||
} | ||
@@ -568,3 +557,3 @@ | ||
* | ||
* @param chunk | ||
* @param chunk {Object} | ||
* @param encoding | ||
@@ -585,5 +574,64 @@ * @param callback | ||
_flush(callback) { | ||
this.resetCache(); | ||
this.reset(); | ||
callback(); | ||
} | ||
/** | ||
* | ||
* @param num {Number|String} | ||
* @param def {Number} | ||
* @param min {Number} | ||
* @param max {Number} | ||
* @returns {Number} | ||
* @private | ||
*/ | ||
static _validateInt(num, def, min, max) { | ||
num = Number.parseInt(num); | ||
return Number.isNaN(num) ? def : num < min ? min : num > max ? max : num; | ||
} | ||
/** | ||
* | ||
* @param num {Number|String} | ||
* @param def {Number} | ||
* @param min {Number} | ||
* @param max {Number} | ||
* @returns {Number} | ||
* @private | ||
*/ | ||
static _validateFloat(num, def, min, max) { | ||
num = Number.parseFloat(num); | ||
return Number.isNaN(num) ? def : num < min ? min : num > max ? max : num; | ||
} | ||
/** | ||
* | ||
* @param bool {Boolean|String|Number} | ||
* @return {Boolean} | ||
* @private | ||
*/ | ||
static _validateBoolean(bool) { | ||
return bool === true || bool === 'true' || bool === 1 || bool === '1'; | ||
} | ||
/** | ||
* | ||
* @param str {String} | ||
* @param arr {String[]} | ||
* @returns {String} | ||
* @private | ||
*/ | ||
static _validateString(str, arr) { | ||
return arr.includes(str) ? str : arr[0]; | ||
} | ||
/** | ||
* | ||
* @param arr (Array} | ||
* @returns {Array|null} | ||
* @private | ||
*/ | ||
static _validateArray(arr) { | ||
return Array.isArray(arr) && arr.length ? arr : null; | ||
} | ||
} | ||
@@ -590,0 +638,0 @@ |
{ | ||
"name": "pam-diff", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"description": "Measure differences between pixel arrays extracted from pam images", | ||
@@ -16,51 +16,51 @@ "main": "index.js", | ||
"gray:all": "npm run gray:all:percent && npm run gray:all:bounds && npm run gray:all:blobs", | ||
"gray:all:percent": "node tests/test_gray --response percent", | ||
"gray:all:bounds": "node tests/test_gray --response bounds", | ||
"gray:all:blobs": "node tests/test_gray --response blobs", | ||
"gray:all:percent": "node tests/test_gray --response percent --pool 2", | ||
"gray:all:bounds": "node tests/test_gray --response bounds --pool 2", | ||
"gray:all:blobs": "node tests/test_gray --response blobs --pool 2", | ||
"gray:mask": "npm run gray:mask:percent && npm run gray:mask:bounds && npm run gray:mask:blobs", | ||
"gray:mask:percent": "node tests/test_gray2 --response percent", | ||
"gray:mask:bounds": "node tests/test_gray2 --response bounds", | ||
"gray:mask:blobs": "node tests/test_gray2 --response blobs", | ||
"gray:mask:percent": "node tests/test_gray2 --response percent --pool 2", | ||
"gray:mask:bounds": "node tests/test_gray2 --response bounds --pool 2", | ||
"gray:mask:blobs": "node tests/test_gray2 --response blobs --pool 2", | ||
"gray:region": "npm run gray:region:percent && npm run gray:region:bounds && npm run gray:region:blobs", | ||
"gray:region:percent": "node tests/test_gray3 --response percent", | ||
"gray:region:bounds": "node tests/test_gray3 --response bounds", | ||
"gray:region:blobs": "node tests/test_gray3 --response blobs", | ||
"gray:region:percent": "node tests/test_gray3 --response percent --pool 2", | ||
"gray:region:bounds": "node tests/test_gray3 --response bounds --pool 2", | ||
"gray:region:blobs": "node tests/test_gray3 --response blobs --pool 2", | ||
"gray:regions": "npm run gray:regions:percent && npm run gray:regions:bounds && npm run gray:regions:blobs", | ||
"gray:regions:percent": "node tests/test_gray4 --response percent", | ||
"gray:regions:bounds": "node tests/test_gray4 --response bounds", | ||
"gray:regions:blobs": "node tests/test_gray4 --response blobs", | ||
"gray:regions:percent": "node tests/test_gray4 --response percent --pool 2", | ||
"gray:regions:bounds": "node tests/test_gray4 --response bounds --pool 2", | ||
"gray:regions:blobs": "node tests/test_gray4 --response blobs --pool 2", | ||
"rgb": "npm run rgb:all && npm run rgb:mask && npm run rgb:region && npm run rgb:regions", | ||
"rgb:all": "npm run rgb:all:percent && npm run rgb:all:bounds && npm run rgb:all:blobs", | ||
"rgb:all:percent": "node tests/test_rgb --response percent", | ||
"rgb:all:bounds": "node tests/test_rgb --response bounds", | ||
"rgb:all:blobs": "node tests/test_rgb --response blobs", | ||
"rgb:all:percent": "node tests/test_rgb --response percent --pool 2", | ||
"rgb:all:bounds": "node tests/test_rgb --response bounds --pool 2", | ||
"rgb:all:blobs": "node tests/test_rgb --response blobs --pool 2", | ||
"rgb:mask": "npm run rgb:mask:percent && npm run rgb:mask:bounds && npm run rgb:mask:blobs", | ||
"rgb:mask:percent": "node tests/test_rgb2 --response percent", | ||
"rgb:mask:bounds": "node tests/test_rgb2 --response bounds", | ||
"rgb:mask:blobs": "node tests/test_rgb2 --response blobs", | ||
"rgb:mask:percent": "node tests/test_rgb2 --response percent --pool 2", | ||
"rgb:mask:bounds": "node tests/test_rgb2 --response bounds --pool 2", | ||
"rgb:mask:blobs": "node tests/test_rgb2 --response blobs --pool 2", | ||
"rgb:region": "npm run rgb:region:percent && npm run rgb:region:bounds && npm run rgb:region:blobs", | ||
"rgb:region:percent": "node tests/test_rgb3 --response percent", | ||
"rgb:region:bounds": "node tests/test_rgb3 --response bounds", | ||
"rgb:region:blobs": "node tests/test_rgb3 --response blobs", | ||
"rgb:region:percent": "node tests/test_rgb3 --response percent --pool 2", | ||
"rgb:region:bounds": "node tests/test_rgb3 --response bounds --pool 2", | ||
"rgb:region:blobs": "node tests/test_rgb3 --response blobs --pool 2", | ||
"rgb:regions": "npm run rgb:regions:percent && npm run rgb:regions:bounds && npm run rgb:regions:blobs", | ||
"rgb:regions:percent": "node tests/test_rgb4 --response percent", | ||
"rgb:regions:bounds": "node tests/test_rgb4 --response bounds", | ||
"rgb:regions:blobs": "node tests/test_rgb4 --response blobs", | ||
"rgb:regions:percent": "node tests/test_rgb4 --response percent --pool 2", | ||
"rgb:regions:bounds": "node tests/test_rgb4 --response bounds --pool 2", | ||
"rgb:regions:blobs": "node tests/test_rgb4 --response blobs --pool 2", | ||
"rgba": "npm run rgba:all && npm run rgba:mask && npm run rgba:region && npm run rgba:regions", | ||
"rgba:all": "npm run rgba:all:percent && npm run rgba:all:bounds && npm run rgba:all:blobs", | ||
"rgba:all:percent": "node tests/test_rgba --response percent", | ||
"rgba:all:bounds": "node tests/test_rgba --response bounds", | ||
"rgba:all:blobs": "node tests/test_rgba -response blobs", | ||
"rgba:all:percent": "node tests/test_rgba --response percent --pool 2", | ||
"rgba:all:bounds": "node tests/test_rgba --response bounds --pool 2", | ||
"rgba:all:blobs": "node tests/test_rgba -response blobs --pool 2", | ||
"rgba:mask": "npm run rgba:mask:percent && npm run rgba:mask:bounds && npm run rgba:mask:blobs", | ||
"rgba:mask:percent": "node tests/test_rgba2 --response percent", | ||
"rgba:mask:bounds": "node tests/test_rgba2 --response bounds", | ||
"rgba:mask:blobs": "node tests/test_rgba2 --response blobs", | ||
"rgba:mask:percent": "node tests/test_rgba2 --response percent --pool 2", | ||
"rgba:mask:bounds": "node tests/test_rgba2 --response bounds --pool 2", | ||
"rgba:mask:blobs": "node tests/test_rgba2 --response blobs --pool 2", | ||
"rgba:region": "npm run rgba:region:percent && npm run rgba:region:bounds && npm run rgba:region:blobs", | ||
"rgba:region:percent": "node tests/test_rgba3 --response percent", | ||
"rgba:region:bounds": "node tests/test_rgba3 --response bounds", | ||
"rgba:region:blobs": "node tests/test_rgba3 --response blobs", | ||
"rgba:region:percent": "node tests/test_rgba3 --response percent --pool 2", | ||
"rgba:region:bounds": "node tests/test_rgba3 --response bounds --pool 2", | ||
"rgba:region:blobs": "node tests/test_rgba3 --response blobs --pool 2", | ||
"rgba:regions": "npm run rgba:regions:percent && npm run rgba:regions:bounds && npm run rgba:regions:blobs", | ||
"rgba:regions:percent": "node tests/test_rgba4 --response percent", | ||
"rgba:regions:bounds": "node tests/test_rgba4 --response bounds", | ||
"rgba:regions:blobs": "node tests/test_rgba4 --response blobs", | ||
"rgba:regions:percent": "node tests/test_rgba4 --response percent --pool 2", | ||
"rgba:regions:bounds": "node tests/test_rgba4 --response bounds --pool 2", | ||
"rgba:regions:blobs": "node tests/test_rgba4 --response blobs --pool 2", | ||
"pam": "npm run pam:gray && npm run pam:rgb && npm run pam:rgba", | ||
@@ -98,3 +98,3 @@ "pam:gray": "node --expose-gc examples/createPam --pixfmt gray --response bounds --draw false --target regions", | ||
"dependencies": { | ||
"pixel-change": "1.1.0", | ||
"pixel-change": "^1.1.0", | ||
"polygon-points": "^0.6.0" | ||
@@ -104,11 +104,11 @@ }, | ||
"@ffmpeg-installer/ffmpeg": "^1.1.0", | ||
"dotenv": "^10.0.0", | ||
"eslint": "^7.32.0", | ||
"eslint-config-prettier": "^7.1.0", | ||
"eslint-plugin-markdown": "^2.2.1", | ||
"eslint-plugin-prettier": "^3.4.1", | ||
"jsdoc": "^3.6.7", | ||
"minimist": "^1.2.5", | ||
"pipe2pam": "^0.6.2", | ||
"prettier": "^2.5.1" | ||
"dotenv": "^16.3.1", | ||
"eslint": "^8.46.0", | ||
"eslint-config-prettier": "^9.0.0", | ||
"eslint-plugin-markdown": "^3.0.1", | ||
"eslint-plugin-prettier": "^5.0.0", | ||
"jsdoc": "^4.0.2", | ||
"minimist": "^1.2.8", | ||
"pipe2pam": "^0.7.0", | ||
"prettier": "^3.0.1" | ||
}, | ||
@@ -123,4 +123,4 @@ "private": false, | ||
"engines": { | ||
"node": ">=10" | ||
"node": ">=14" | ||
} | ||
} |
# pam-diff | ||
###### [![Build Status](https://github.com/kevinGodell/pam-diff/workflows/build/badge.svg)](https://github.com/kevinGodell/pam-diff/actions?query=workflow%3Abuild) [![Build Status](https://ci.appveyor.com/api/projects/status/hu6qw285sm6vfwtd/branch/master?svg=true)](https://ci.appveyor.com/project/kevinGodell/pam-diff/branch/master) [![GitHub Issues](https://img.shields.io/github/issues/kevinGodell/pam-diff.svg)](https://github.com/kevinGodell/pam-diff/issues) [![GitHub License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/kevinGodell/pam-diff/master/LICENSE) [![npm](https://img.shields.io/npm/dt/pam-diff.svg?style=flat-square)](https://www.npmjs.com/package/pam-diff) | ||
###### [![Buy me a coffee](https://img.shields.io/badge/-buy%20me%20a%20coffee-red?logo=buy%20me%20a%20coffee)](https://buymeacoffee.com/kevinGodell) [![Build Status](https://github.com/kevinGodell/pam-diff/workflows/build/badge.svg)](https://github.com/kevinGodell/pam-diff/actions?query=workflow%3Abuild) [![Build Status](https://ci.appveyor.com/api/projects/status/hu6qw285sm6vfwtd/branch/master?svg=true)](https://ci.appveyor.com/project/kevinGodell/pam-diff/branch/master) [![GitHub Issues](https://img.shields.io/github/issues/kevinGodell/pam-diff.svg)](https://github.com/kevinGodell/pam-diff/issues) [![GitHub License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/kevinGodell/pam-diff/master/LICENSE) [![npm](https://img.shields.io/npm/dt/pam-diff.svg?style=flat-square)](https://www.npmjs.com/package/pam-diff) | ||
@@ -15,4 +15,13 @@ Measure differences between pixel arrays extracted from pam images. Works well with node module [pipe2pam](https://www.npmjs.com/package/pipe2pam) to extract pam images from an ffmpeg pipe. Supported **_tupltypes_** are **_rgb_**, **_rgb_alpha_**, and **_grayscale_**. It is currently being used for a video motion detection project. | ||
###### _version 1.1.0:_ Percent is now a float to allow for more precise results. Sync option is removed. | ||
###### _version 1.2.0:_ | ||
* Dropping support for node.js < 14. | ||
* Data event emitted for all results returned from [pixel-change](https://www.npmjs.com/package/pixel-change). | ||
* Initialized event emitted after first chunk parsed. | ||
* Debug object attached to output if debug property is set to true. | ||
* Updated [docs](https://kevingodell.github.io/pam-diff/PamDiff.html) to show deprecations. | ||
###### _version 1.1.0:_ | ||
* Percent is now a float to allow for more precise results. | ||
* Sync option is removed. | ||
## Usage Options: | ||
@@ -43,5 +52,5 @@ | ||
{ x: 0, y: 0 }, | ||
{ x: 0, y: 225 }, | ||
{ x: 100, y: 225 }, | ||
{ x: 100, y: 0 }, | ||
{ x: 0, y: 224 }, | ||
{ x: 99, y: 224 }, | ||
{ x: 99, y: 0 }, | ||
], | ||
@@ -55,5 +64,5 @@ }; | ||
{ x: 100, y: 0 }, | ||
{ x: 100, y: 225 }, | ||
{ x: 200, y: 225 }, | ||
{ x: 200, y: 0 }, | ||
{ x: 100, y: 224 }, | ||
{ x: 199, y: 224 }, | ||
{ x: 199, y: 0 }, | ||
], | ||
@@ -69,3 +78,3 @@ }; | ||
- To use this option, create a regions array and set the mask option to true. | ||
- `difference` and `percent` of the individual region is ignored. Set a global value. | ||
- `difference` and `percent` of the individual region is ignored. Set global values. | ||
@@ -77,5 +86,5 @@ ```javascript | ||
{ x: 0, y: 0 }, | ||
{ x: 0, y: 225 }, | ||
{ x: 100, y: 225 }, | ||
{ x: 100, y: 0 }, | ||
{ x: 0, y: 224 }, | ||
{ x: 99, y: 224 }, | ||
{ x: 99, y: 0 }, | ||
], | ||
@@ -87,5 +96,5 @@ }; | ||
{ x: 100, y: 0 }, | ||
{ x: 100, y: 225 }, | ||
{ x: 200, y: 225 }, | ||
{ x: 200, y: 0 }, | ||
{ x: 100, y: 224 }, | ||
{ x: 199, y: 224 }, | ||
{ x: 199, y: 0 }, | ||
], | ||
@@ -100,5 +109,5 @@ }; | ||
1. event | ||
- A _diff_ event will be emitted with a data object passed as the only argument. | ||
- A _diff_ event will be emitted when there is a pixel difference detection. | ||
```javascript | ||
```javascript | ||
pamDiff.on('diff', data => { | ||
@@ -109,5 +118,14 @@ console.log(data); | ||
2. callback | ||
- A _data_ event will be emitted regardless of pixel difference detection. | ||
```javascript | ||
pamDiff.on('data', data => { | ||
console.log(data); | ||
}); | ||
``` | ||
2. callback (deprecated) | ||
- A _callback_ function will be called with a data object passed as the only argument. | ||
- The callback can be passed as the 2nd argument to the constructor, or it can be added later. | ||
- Deprecated. Scheduled to be removed. | ||
@@ -114,0 +132,0 @@ ```javascript |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
29377
565
239
Updatedpixel-change@^1.1.0