mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 10:30:15 +02:00
Add pixel-derived image statistics via vips_stats (#915)
This commit is contained in:
parent
dfaa39fa5d
commit
d6aee8e5ba
@ -86,6 +86,7 @@
|
||||
'sources': [
|
||||
'src/common.cc',
|
||||
'src/metadata.cc',
|
||||
'src/stats.cc',
|
||||
'src/operations.cc',
|
||||
'src/pipeline.cc',
|
||||
'src/sharp.cc',
|
||||
|
@ -67,6 +67,42 @@ image
|
||||
|
||||
Returns **([Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)> | Sharp)**
|
||||
|
||||
## stats
|
||||
|
||||
Access to pixel-derived image statistics for every channel in the image
|
||||
A Promises/A+ promise is returned when `callback` is not provided.
|
||||
|
||||
- `channels`: Array of channel statistics for each channel in the image. Each channel statistic contains
|
||||
- `min` (minimum value in the channel)
|
||||
- `max` (maximum value in the channel)
|
||||
- `sum` (sum of all values in a channel)
|
||||
- `squaresSum` (sum of squared values in a channel)
|
||||
- `mean` (mean of the values in a channel)
|
||||
- `stdev` (standard deviation for the values in a channel)
|
||||
- `minX` (x-coordinate of one of the pixel where the minimum lies)
|
||||
- `minY` (y-coordinate of one of the pixel where the minimum lies)
|
||||
- `maxX` (x-coordinate of one of the pixel where the maximum lies)
|
||||
- `maxY` (y-coordinate of one of the pixel where the maximum lies)
|
||||
- `isOpaque`: Value to identify if the image is opaque or transparent, based on the presence and use of alpha channel
|
||||
|
||||
**Parameters**
|
||||
|
||||
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)?** called with the arguments `(err, metadata)`
|
||||
|
||||
**Examples**
|
||||
|
||||
```javascript
|
||||
const image = sharp(inputJpg);
|
||||
image
|
||||
.stats()
|
||||
.then(function(stats) {
|
||||
// stats contains the channel-wise statistics array and the isOpaque value
|
||||
})
|
||||
```
|
||||
|
||||
Returns **([Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)> | Sharp)**
|
||||
|
||||
|
||||
## limitInputPixels
|
||||
|
||||
Do not process input images where the number of pixels (width _ height) exceeds this limit.
|
||||
|
70
lib/input.js
70
lib/input.js
@ -238,6 +238,75 @@ function metadata (callback) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Access to pixel-derived image statistics for every channel in the image
|
||||
* A Promise/A+ promise is returned when `callback` is not provided.
|
||||
*
|
||||
* - `channels`: Array of channel statistics for each channel in the image. Each channel statistic contains
|
||||
* - `min` (minimum value in the channel)
|
||||
* - `max` (maximum value in the channel)
|
||||
* - `sum` (sum of all values in a channel)
|
||||
* - `squaresSum` (sum of squared values in a channel)
|
||||
* - `mean` (mean of the values in a channel)
|
||||
* - `stdev` (standard deviation for the values in a channel)
|
||||
* - `minX` (x-coordinate of one of the pixel where the minimum lies)
|
||||
* - `minY` (y-coordinate of one of the pixel where the minimum lies)
|
||||
* - `maxX` (x-coordinate of one of the pixel where the maximum lies)
|
||||
* - `maxY` (y-coordinate of one of the pixel where the maximum lies)
|
||||
* - `isOpaque`: Value to identify if the image is opaque or transparent, based on the presence and use of alpha channel
|
||||
*
|
||||
* @example
|
||||
* const image = sharp(inputJpg);
|
||||
* image
|
||||
* .stats()
|
||||
* .then(function(stats) {
|
||||
* // stats contains the channel-wise statistics array and the isOpaque value
|
||||
* })
|
||||
*
|
||||
*
|
||||
* @param {Function} [callback] - called with the arguments `(err, stats)`
|
||||
* @returns {Promise<Object>|Sharp}
|
||||
*/
|
||||
function stats (callback) {
|
||||
const that = this;
|
||||
if (is.fn(callback)) {
|
||||
if (this._isStreamInput()) {
|
||||
this.on('finish', function () {
|
||||
that._flattenBufferIn();
|
||||
sharp.stats(that.options, callback);
|
||||
});
|
||||
} else {
|
||||
sharp.stats(this.options, callback);
|
||||
}
|
||||
return this;
|
||||
} else {
|
||||
if (this._isStreamInput()) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
that.on('finish', function () {
|
||||
that._flattenBufferIn();
|
||||
sharp.stats(that.options, function (err, stats) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(stats);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return new Promise(function (resolve, reject) {
|
||||
sharp.stats(that.options, function (err, stats) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(stats);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not process input images where the number of pixels (width * height) exceeds this limit.
|
||||
* Assumes image dimensions contained in the input metadata can be trusted.
|
||||
@ -289,6 +358,7 @@ module.exports = function (Sharp) {
|
||||
// Public
|
||||
clone,
|
||||
metadata,
|
||||
stats,
|
||||
limitInputPixels,
|
||||
sequentialRead
|
||||
].forEach(function (f) {
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "metadata.h"
|
||||
#include "pipeline.h"
|
||||
#include "utilities.h"
|
||||
#include "stats.h"
|
||||
|
||||
NAN_MODULE_INIT(init) {
|
||||
vips_init("sharp");
|
||||
@ -46,6 +47,8 @@ NAN_MODULE_INIT(init) {
|
||||
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(format)).ToLocalChecked());
|
||||
Nan::Set(target, Nan::New("_maxColourDistance").ToLocalChecked(),
|
||||
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(_maxColourDistance)).ToLocalChecked());
|
||||
Nan::Set(target, Nan::New("stats").ToLocalChecked(),
|
||||
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(stats)).ToLocalChecked());
|
||||
}
|
||||
|
||||
NODE_MODULE(sharp, init)
|
||||
|
188
src/stats.cc
Normal file
188
src/stats.cc
Normal file
@ -0,0 +1,188 @@
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#include <node.h>
|
||||
#include <nan.h>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
#include "stats.h"
|
||||
|
||||
class StatsWorker : public Nan::AsyncWorker {
|
||||
public:
|
||||
StatsWorker(
|
||||
Nan::Callback *callback, StatsBaton *baton, Nan::Callback *debuglog,
|
||||
std::vector<v8::Local<v8::Object>> const buffersToPersist) :
|
||||
Nan::AsyncWorker(callback), baton(baton), debuglog(debuglog),
|
||||
buffersToPersist(buffersToPersist) {
|
||||
// Protect Buffer objects from GC, keyed on index
|
||||
std::accumulate(buffersToPersist.begin(), buffersToPersist.end(), 0,
|
||||
[this](uint32_t index, v8::Local<v8::Object> const buffer) -> uint32_t {
|
||||
SaveToPersistent(index, buffer);
|
||||
return index + 1;
|
||||
});
|
||||
}
|
||||
~StatsWorker() {}
|
||||
|
||||
const int STAT_MIN_INDEX = 0;
|
||||
const int STAT_MAX_INDEX = 1;
|
||||
const int STAT_SUM_INDEX = 2;
|
||||
const int STAT_SQ_SUM_INDEX = 3;
|
||||
const int STAT_MEAN_INDEX = 4;
|
||||
const int STAT_STDEV_INDEX = 5;
|
||||
const int STAT_MINX_INDEX = 6;
|
||||
const int STAT_MINY_INDEX = 7;
|
||||
const int STAT_MAXX_INDEX = 8;
|
||||
const int STAT_MAXY_INDEX = 9;
|
||||
|
||||
void Execute() {
|
||||
// Decrement queued task counter
|
||||
g_atomic_int_dec_and_test(&sharp::counterQueue);
|
||||
using Nan::New;
|
||||
using Nan::Set;
|
||||
using sharp::MaximumImageAlpha;
|
||||
|
||||
vips::VImage image;
|
||||
vips::VImage stats;
|
||||
sharp::ImageType imageType = sharp::ImageType::UNKNOWN;
|
||||
|
||||
try {
|
||||
std::tie(image, imageType) = OpenInput(baton->input, baton->accessMethod);
|
||||
} catch (vips::VError const &err) {
|
||||
(baton->err).append(err.what());
|
||||
}
|
||||
if (imageType != sharp::ImageType::UNKNOWN) {
|
||||
try {
|
||||
stats = image.stats();
|
||||
int bands = image.bands();
|
||||
double const max = MaximumImageAlpha(image.interpretation());
|
||||
for (int b = 1; b <= bands; b++) {
|
||||
ChannelStats cStats(static_cast<int>(stats.getpoint(STAT_MIN_INDEX, b).front()),
|
||||
static_cast<int>(stats.getpoint(STAT_MAX_INDEX, b).front()),
|
||||
stats.getpoint(STAT_SUM_INDEX, b).front(), stats.getpoint(STAT_SQ_SUM_INDEX, b).front(),
|
||||
stats.getpoint(STAT_MEAN_INDEX, b).front(), stats.getpoint(STAT_STDEV_INDEX, b).front(),
|
||||
static_cast<int>(stats.getpoint(STAT_MINX_INDEX, b).front()),
|
||||
static_cast<int>(stats.getpoint(STAT_MINY_INDEX, b).front()),
|
||||
static_cast<int>(stats.getpoint(STAT_MAXX_INDEX, b).front()),
|
||||
static_cast<int>(stats.getpoint(STAT_MAXY_INDEX, b).front()));
|
||||
baton->channelStats.push_back(cStats);
|
||||
}
|
||||
|
||||
// alpha layer is there and the last band i.e. alpha has its max value greater than 0)
|
||||
if (sharp::HasAlpha(image) && stats.getpoint(STAT_MIN_INDEX, bands).front() != max) {
|
||||
baton->isOpaque = false;
|
||||
}
|
||||
} catch (vips::VError const &err) {
|
||||
(baton->err).append(err.what());
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
vips_error_clear();
|
||||
vips_thread_shutdown();
|
||||
}
|
||||
|
||||
void HandleOKCallback() {
|
||||
using Nan::New;
|
||||
using Nan::Set;
|
||||
Nan::HandleScope();
|
||||
|
||||
v8::Local<v8::Value> argv[2] = { Nan::Null(), Nan::Null() };
|
||||
if (!baton->err.empty()) {
|
||||
argv[0] = Nan::Error(baton->err.data());
|
||||
} else {
|
||||
// Stats Object
|
||||
v8::Local<v8::Object> info = New<v8::Object>();
|
||||
v8::Local<v8::Array> channels = New<v8::Array>();
|
||||
|
||||
std::vector<ChannelStats>::iterator it;
|
||||
int i = 0;
|
||||
for (it=baton->channelStats.begin() ; it < baton->channelStats.end(); it++, i++) {
|
||||
v8::Local<v8::Object> channelStat = New<v8::Object>();
|
||||
Set(channelStat, New("min").ToLocalChecked(), New<v8::Number>(it->min));
|
||||
Set(channelStat, New("max").ToLocalChecked(), New<v8::Number>(it->max));
|
||||
Set(channelStat, New("sum").ToLocalChecked(), New<v8::Number>(it->sum));
|
||||
Set(channelStat, New("squaresSum").ToLocalChecked(), New<v8::Number>(it->squaresSum));
|
||||
Set(channelStat, New("mean").ToLocalChecked(), New<v8::Number>(it->mean));
|
||||
Set(channelStat, New("stdev").ToLocalChecked(), New<v8::Number>(it->stdev));
|
||||
Set(channelStat, New("minX").ToLocalChecked(), New<v8::Number>(it->minX));
|
||||
Set(channelStat, New("minY").ToLocalChecked(), New<v8::Number>(it->minY));
|
||||
Set(channelStat, New("maxX").ToLocalChecked(), New<v8::Number>(it->maxX));
|
||||
Set(channelStat, New("maxY").ToLocalChecked(), New<v8::Number>(it->maxY));
|
||||
channels->Set(i, channelStat);
|
||||
}
|
||||
|
||||
Set(info, New("channels").ToLocalChecked(), channels);
|
||||
Set(info, New("isOpaque").ToLocalChecked(), New<v8::Boolean>(baton->isOpaque));
|
||||
argv[1] = info;
|
||||
}
|
||||
|
||||
// Dispose of Persistent wrapper around input Buffers so they can be garbage collected
|
||||
std::accumulate(buffersToPersist.begin(), buffersToPersist.end(), 0,
|
||||
[this](uint32_t index, v8::Local<v8::Object> const buffer) -> uint32_t {
|
||||
GetFromPersistent(index);
|
||||
return index + 1;
|
||||
});
|
||||
delete baton->input;
|
||||
delete baton;
|
||||
|
||||
// Handle warnings
|
||||
std::string warning = sharp::VipsWarningPop();
|
||||
while (!warning.empty()) {
|
||||
v8::Local<v8::Value> message[1] = { New(warning).ToLocalChecked() };
|
||||
debuglog->Call(1, message);
|
||||
warning = sharp::VipsWarningPop();
|
||||
}
|
||||
|
||||
// Return to JavaScript
|
||||
callback->Call(2, argv);
|
||||
}
|
||||
|
||||
private:
|
||||
StatsBaton* baton;
|
||||
Nan::Callback *debuglog;
|
||||
std::vector<v8::Local<v8::Object>> buffersToPersist;
|
||||
};
|
||||
|
||||
/*
|
||||
stats(options, callback)
|
||||
*/
|
||||
NAN_METHOD(stats) {
|
||||
using sharp::AttrTo;
|
||||
|
||||
// Input Buffers must not undergo GC compaction during processing
|
||||
std::vector<v8::Local<v8::Object>> buffersToPersist;
|
||||
|
||||
// V8 objects are converted to non-V8 types held in the baton struct
|
||||
StatsBaton *baton = new StatsBaton;
|
||||
v8::Local<v8::Object> options = info[0].As<v8::Object>();
|
||||
|
||||
// Input
|
||||
baton->input = sharp::CreateInputDescriptor(sharp::AttrAs<v8::Object>(options, "input"), buffersToPersist);
|
||||
baton->accessMethod = AttrTo<bool>(options, "sequentialRead") ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
|
||||
|
||||
// Function to notify of libvips warnings
|
||||
Nan::Callback *debuglog = new Nan::Callback(sharp::AttrAs<v8::Function>(options, "debuglog"));
|
||||
|
||||
// Join queue for worker thread
|
||||
Nan::Callback *callback = new Nan::Callback(info[1].As<v8::Function>());
|
||||
Nan::AsyncQueueWorker(new StatsWorker(callback, baton, debuglog, buffersToPersist));
|
||||
|
||||
// Increment queued task counter
|
||||
g_atomic_int_inc(&sharp::counterQueue);
|
||||
}
|
65
src/stats.h
Normal file
65
src/stats.h
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SRC_STATS_H_
|
||||
#define SRC_STATS_H_
|
||||
|
||||
#include <string>
|
||||
#include <nan.h>
|
||||
|
||||
#include "./common.h"
|
||||
|
||||
struct ChannelStats {
|
||||
// stats per channel
|
||||
int min;
|
||||
int max;
|
||||
double sum;
|
||||
double squaresSum;
|
||||
double mean;
|
||||
double stdev;
|
||||
int minX;
|
||||
int minY;
|
||||
int maxX;
|
||||
int maxY;
|
||||
|
||||
ChannelStats():
|
||||
min(0), max(0), sum(0), squaresSum(0), mean(0), stdev(0)
|
||||
, minX(0), minY(0), maxX(0), maxY(0) {}
|
||||
|
||||
ChannelStats(int minVal, int maxVal, double sumVal, double squaresSumVal,
|
||||
double meanVal, double stdevVal, int minXVal, int minYVal, int maxXVal, int maxYVal):
|
||||
min(minVal), max(maxVal), sum(sumVal), squaresSum(squaresSumVal),
|
||||
mean(meanVal), stdev(stdevVal), minX(minXVal), minY(minYVal), maxX(maxXVal), maxY(maxYVal) {}
|
||||
};
|
||||
|
||||
struct StatsBaton {
|
||||
// Input
|
||||
sharp::InputDescriptor *input;
|
||||
VipsAccess accessMethod;
|
||||
|
||||
// Output
|
||||
std::vector<ChannelStats> channelStats;
|
||||
bool isOpaque;
|
||||
|
||||
std::string err;
|
||||
|
||||
StatsBaton():
|
||||
input(nullptr),
|
||||
isOpaque(true)
|
||||
{}
|
||||
};
|
||||
|
||||
NAN_METHOD(stats);
|
||||
|
||||
#endif // SRC_STATS_H_
|
BIN
test/fixtures/full-transparent.png
vendored
Normal file
BIN
test/fixtures/full-transparent.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 148 B |
1
test/fixtures/index.js
vendored
1
test/fixtures/index.js
vendored
@ -71,6 +71,7 @@ module.exports = {
|
||||
|
||||
inputPng: getPath('50020484-00001.png'), // http://c.searspartsdirect.com/lis_png/PLDM/50020484-00001.png
|
||||
inputPngWithTransparency: getPath('blackbug.png'), // public domain
|
||||
inputPngCompleteTransparency: getPath('full-transparent.png'),
|
||||
inputPngWithGreyAlpha: getPath('grey-8bit-alpha.png'),
|
||||
inputPngWithOneColor: getPath('2x2_fdcce6.png'),
|
||||
inputPngWithTransparency16bit: getPath('tbgn2c16.png'), // http://www.schaik.com/pngsuite/tbgn2c16.png
|
||||
|
607
test/unit/stats.js
Normal file
607
test/unit/stats.js
Normal file
@ -0,0 +1,607 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const assert = require('assert');
|
||||
|
||||
const sharp = require('../../');
|
||||
const fixtures = require('../fixtures');
|
||||
|
||||
// Test Helpers
|
||||
var threshold = 0.001;
|
||||
function isInAcceptableRange (actual, expected) {
|
||||
return actual >= ((1 - threshold) * expected) && actual <= ((1 + threshold) * expected);
|
||||
}
|
||||
function isInRange (actual, min, max) {
|
||||
return actual >= min && actual <= max;
|
||||
}
|
||||
function isInteger (val) {
|
||||
return Number.isInteger(val);
|
||||
}
|
||||
|
||||
describe('Image Stats', function () {
|
||||
it('JPEG', function (done) {
|
||||
sharp(fixtures.inputJpg).stats(function (err, stats) {
|
||||
if (err) throw err;
|
||||
|
||||
assert.strictEqual(true, stats.isOpaque);
|
||||
|
||||
// red channel
|
||||
assert.strictEqual(0, stats.channels[0]['min']);
|
||||
assert.strictEqual(255, stats.channels[0]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['sum'], 615101275));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['squaresSum'], 83061892917));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['mean'], 101.44954540768993));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['stdev'], 58.373870588815414));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minY'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxY'], 0, 2725));
|
||||
|
||||
// green channel
|
||||
assert.strictEqual(0, stats.channels[1]['min']);
|
||||
assert.strictEqual(255, stats.channels[1]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['sum'], 462824115));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['squaresSum'], 47083677255));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['mean'], 76.33425255128337));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['stdev'], 44.03023262954866));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['minX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['minY'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['maxX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['maxY'], 0, 2725));
|
||||
|
||||
// blue channel
|
||||
assert.strictEqual(0, stats.channels[2]['min']);
|
||||
assert.strictEqual(255, stats.channels[2]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['sum'], 372986756));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['squaresSum'], 32151543524));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['mean'], 61.51724663436759));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['stdev'], 38.96702865090125));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['minX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['minY'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['maxX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['maxY'], 0, 2725));
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('PNG without transparency', function (done) {
|
||||
sharp(fixtures.inputPng).stats(function (err, stats) {
|
||||
if (err) throw err;
|
||||
|
||||
assert.strictEqual(true, stats.isOpaque);
|
||||
|
||||
// red channel
|
||||
assert.strictEqual(0, stats.channels[0]['min']);
|
||||
assert.strictEqual(255, stats.channels[0]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['sum'], 1391368230));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['squaresSum'], 354798898650));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['mean'], 238.8259925648822));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['stdev'], 62.15121915523771));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minX'], 0, 2809));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minY'], 0, 2074));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxX'], 0, 2809));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxY'], 0, 2074));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('PNG with transparency', function (done) {
|
||||
sharp(fixtures.inputPngWithTransparency).stats(function (err, stats) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(false, stats.isOpaque);
|
||||
|
||||
// red channel
|
||||
assert.strictEqual(0, stats.channels[0]['min']);
|
||||
assert.strictEqual(255, stats.channels[0]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['sum'], 795678795));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['squaresSum'], 202898092725));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['mean'], 252.9394769668579));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['stdev'], 22.829537532816));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minX'], 0, 2048));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minY'], 0, 1536));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxX'], 0, 2048));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxY'], 0, 1536));
|
||||
|
||||
// green channel
|
||||
assert.strictEqual(0, stats.channels[1]['min']);
|
||||
assert.strictEqual(255, stats.channels[1]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['sum'], 795678795));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['squaresSum'], 202898092725));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['mean'], 252.9394769668579));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['stdev'], 22.829537532816));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['minX'], 0, 2048));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['minY'], 0, 1536));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['maxX'], 0, 2048));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['maxY'], 0, 1536));
|
||||
|
||||
// blue channel
|
||||
assert.strictEqual(0, stats.channels[2]['min']);
|
||||
assert.strictEqual(255, stats.channels[2]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['sum'], 795678795));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['squaresSum'], 202898092725));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['mean'], 252.9394769668579));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['stdev'], 22.829537532816));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['minX'], 0, 2048));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['minY'], 0, 1536));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['maxX'], 0, 2048));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['maxY'], 0, 1536));
|
||||
|
||||
// alpha channel
|
||||
assert.strictEqual(0, stats.channels[3]['min']);
|
||||
assert.strictEqual(255, stats.channels[3]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[3]['sum'], 5549142));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[3]['squaresSum'], 1333571132));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[3]['mean'], 1.7640247344970703));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[3]['stdev'], 20.51387814157297));
|
||||
assert.strictEqual(true, isInteger(stats.channels[3]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[3]['minX'], 0, 2048));
|
||||
assert.strictEqual(true, isInteger(stats.channels[3]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[3]['minY'], 0, 1536));
|
||||
assert.strictEqual(true, isInteger(stats.channels[3]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[3]['maxX'], 0, 2048));
|
||||
assert.strictEqual(true, isInteger(stats.channels[3]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[3]['maxY'], 0, 1536));
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('PNG fully transparent', function (done) {
|
||||
sharp(fixtures.inputPngCompleteTransparency).stats(function (err, stats) {
|
||||
if (err) throw err;
|
||||
|
||||
assert.strictEqual(false, stats.isOpaque);
|
||||
|
||||
// alpha channel
|
||||
assert.strictEqual(0, stats.channels[3]['min']);
|
||||
assert.strictEqual(0, stats.channels[3]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[3]['sum'], 0));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[3]['squaresSum'], 0));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[3]['mean'], 0));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[3]['stdev'], 0));
|
||||
assert.strictEqual(true, isInteger(stats.channels[3]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[3]['minX'], 0, 300));
|
||||
assert.strictEqual(true, isInteger(stats.channels[3]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[3]['minY'], 0, 300));
|
||||
assert.strictEqual(true, isInteger(stats.channels[3]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[3]['maxX'], 0, 300));
|
||||
assert.strictEqual(true, isInteger(stats.channels[3]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[3]['maxY'], 0, 300));
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Tiff', function (done) {
|
||||
sharp(fixtures.inputTiff).stats(function (err, stats) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(true, stats.isOpaque);
|
||||
|
||||
// red channel
|
||||
assert.strictEqual(0, stats.channels[0]['min']);
|
||||
assert.strictEqual(255, stats.channels[0]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['sum'], 1887266220));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['squaresSum'], 481252886100));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['mean'], 235.81772349417824));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['stdev'], 67.25712856093298));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minX'], 0, 2464));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minY'], 0, 3248));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxX'], 0, 2464));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxY'], 0, 3248));
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('WebP', function (done) {
|
||||
sharp(fixtures.inputWebP).stats(function (err, stats) {
|
||||
if (err) throw err;
|
||||
|
||||
assert.strictEqual(true, stats.isOpaque);
|
||||
|
||||
// red channel
|
||||
assert.strictEqual(0, stats.channels[0]['min']);
|
||||
assert.strictEqual(255, stats.channels[0]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['sum'], 83291370));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['squaresSum'], 11379783198));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['mean'], 105.36169496842616));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['stdev'], 57.39412151419967));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minX'], 0, 1024));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minY'], 0, 772));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxX'], 0, 1024));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxY'], 0, 772));
|
||||
|
||||
// green channel
|
||||
assert.strictEqual(0, stats.channels[1]['min']);
|
||||
assert.strictEqual(255, stats.channels[1]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['sum'], 120877425));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['squaresSum'], 20774687595));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['mean'], 152.9072025279307));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['stdev'], 53.84143349689916));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['minX'], 0, 1024));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['minY'], 0, 772));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['maxX'], 0, 1024));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['maxY'], 0, 772));
|
||||
|
||||
// blue channel
|
||||
assert.strictEqual(0, stats.channels[2]['min']);
|
||||
assert.strictEqual(255, stats.channels[2]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['sum'], 138938859));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['squaresSum'], 28449125593));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['mean'], 175.75450711423252));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['stdev'], 71.39929031070358));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['minX'], 0, 1024));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['minY'], 0, 772));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['maxX'], 0, 1024));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['maxY'], 0, 772));
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('GIF', function (done) {
|
||||
sharp(fixtures.inputGif).stats(function (err, stats) {
|
||||
if (err) throw err;
|
||||
|
||||
assert.strictEqual(true, stats.isOpaque);
|
||||
|
||||
// red channel
|
||||
assert.strictEqual(35, stats.channels[0]['min']);
|
||||
assert.strictEqual(254, stats.channels[0]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['sum'], 56088385));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['squaresSum'], 8002132113));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['mean'], 131.53936444652908));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['stdev'], 38.26389131415863));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minX'], 0, 800));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minY'], 0, 533));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxX'], 0, 800));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxY'], 0, 533));
|
||||
|
||||
// green channel
|
||||
assert.strictEqual(43, stats.channels[1]['min']);
|
||||
assert.strictEqual(255, stats.channels[1]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['sum'], 58612156));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['squaresSum'], 8548344254));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['mean'], 137.45815196998123));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['stdev'], 33.955424103758205));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['minX'], 0, 800));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['minY'], 0, 533));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['maxX'], 0, 800));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['maxY'], 0, 533));
|
||||
|
||||
// blue channel
|
||||
assert.strictEqual(51, stats.channels[2]['min']);
|
||||
assert.strictEqual(254, stats.channels[2]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['sum'], 49628525));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['squaresSum'], 6450556071));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['mean'], 116.38959896810506));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['stdev'], 39.7669551046809));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['minX'], 0, 800));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['minY'], 0, 533));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['maxX'], 0, 800));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['maxY'], 0, 533));
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Grayscale GIF with alpha', function (done) {
|
||||
sharp(fixtures.inputGifGreyPlusAlpha).stats(function (err, stats) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(false, stats.isOpaque);
|
||||
|
||||
// gray channel
|
||||
assert.strictEqual(0, stats.channels[0]['min']);
|
||||
assert.strictEqual(101, stats.channels[0]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['sum'], 101));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['squaresSum'], 10201));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['mean'], 50.5));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['stdev'], 71.4177848998413));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minX'], 0, 2));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minY'], 0, 1));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxX'], 0, 2));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxY'], 0, 1));
|
||||
|
||||
// alpha channel
|
||||
assert.strictEqual(0, stats.channels[1]['min']);
|
||||
assert.strictEqual(255, stats.channels[1]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['sum'], 255));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['squaresSum'], 65025));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['mean'], 127.5));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['stdev'], 180.31222920256963));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['minX'], 0, 2));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['minY'], 0, 1));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['maxX'], 0, 2));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['maxY'], 0, 1));
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Stream in, Callback out', function (done) {
|
||||
const readable = fs.createReadStream(fixtures.inputJpg);
|
||||
const pipeline = sharp().stats(function (err, stats) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(true, stats.isOpaque);
|
||||
|
||||
// red channel
|
||||
assert.strictEqual(0, stats.channels[0]['min']);
|
||||
assert.strictEqual(255, stats.channels[0]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['sum'], 615101275));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['squaresSum'], 83061892917));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['mean'], 101.44954540768993));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['stdev'], 58.373870588815414));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minY'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxY'], 0, 2725));
|
||||
|
||||
// green channel
|
||||
assert.strictEqual(0, stats.channels[1]['min']);
|
||||
assert.strictEqual(255, stats.channels[1]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['sum'], 462824115));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['squaresSum'], 47083677255));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['mean'], 76.33425255128337));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['stdev'], 44.03023262954866));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['minX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['minY'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['maxX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1]['maxY'], 0, 2725));
|
||||
|
||||
// blue channel
|
||||
assert.strictEqual(0, stats.channels[2]['min']);
|
||||
assert.strictEqual(255, stats.channels[2]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['sum'], 372986756));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['squaresSum'], 32151543524));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['mean'], 61.51724663436759));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['stdev'], 38.96702865090125));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['minX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['minY'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['maxX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2]['maxY'], 0, 2725));
|
||||
|
||||
done();
|
||||
});
|
||||
readable.pipe(pipeline);
|
||||
});
|
||||
|
||||
it('Stream in, Promise out', function () {
|
||||
const pipeline = sharp();
|
||||
|
||||
fs.createReadStream(fixtures.inputJpg).pipe(pipeline);
|
||||
|
||||
return pipeline.stats().then(function (stats) {
|
||||
assert.strictEqual(true, stats.isOpaque);
|
||||
|
||||
// red channel
|
||||
assert.strictEqual(0, stats.channels[0]['min']);
|
||||
assert.strictEqual(255, stats.channels[0]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['sum'], 615101275));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['squaresSum'], 83061892917));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['mean'], 101.44954540768993));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['stdev'], 58.373870588815414));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minY'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxY'], 0, 2725));
|
||||
|
||||
// green channel
|
||||
assert.strictEqual(0, stats.channels[1]['min']);
|
||||
assert.strictEqual(255, stats.channels[1]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['sum'], 462824115));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['squaresSum'], 47083677255));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['mean'], 76.33425255128337));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['stdev'], 44.03023262954866));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minY'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxY'], 0, 2725));
|
||||
|
||||
// blue channel
|
||||
assert.strictEqual(0, stats.channels[2]['min']);
|
||||
assert.strictEqual(255, stats.channels[2]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['sum'], 372986756));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['squaresSum'], 32151543524));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['mean'], 61.51724663436759));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['stdev'], 38.96702865090125));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minY'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxY'], 0, 2725));
|
||||
}).catch(function (err) {
|
||||
throw err;
|
||||
});
|
||||
});
|
||||
|
||||
it('File in, Promise out', function () {
|
||||
return sharp(fixtures.inputJpg).stats().then(function (stats) {
|
||||
assert.strictEqual(true, stats.isOpaque);
|
||||
|
||||
// red channel
|
||||
assert.strictEqual(0, stats.channels[0]['min']);
|
||||
assert.strictEqual(255, stats.channels[0]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['sum'], 615101275));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['squaresSum'], 83061892917));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['mean'], 101.44954540768993));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0]['stdev'], 58.373870588815414));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minY'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxY'], 0, 2725));
|
||||
|
||||
// green channel
|
||||
assert.strictEqual(0, stats.channels[1]['min']);
|
||||
assert.strictEqual(255, stats.channels[1]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['sum'], 462824115));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['squaresSum'], 47083677255));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['mean'], 76.33425255128337));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1]['stdev'], 44.03023262954866));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minY'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxY'], 0, 2725));
|
||||
|
||||
// blue channel
|
||||
assert.strictEqual(0, stats.channels[2]['min']);
|
||||
assert.strictEqual(255, stats.channels[2]['max']);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['sum'], 372986756));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['squaresSum'], 32151543524));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['mean'], 61.51724663436759));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2]['stdev'], 38.96702865090125));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['minY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['minY'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxX']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxX'], 0, 2725));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0]['maxY']));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0]['maxY'], 0, 2725));
|
||||
}).catch(function (err) {
|
||||
throw err;
|
||||
});
|
||||
});
|
||||
|
||||
it('File input with corrupt header fails gracefully', function (done) {
|
||||
sharp(fixtures.inputJpgWithCorruptHeader)
|
||||
.stats(function (err) {
|
||||
assert.strictEqual(true, !!err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('File input with corrupt header fails gracefully, Promise out', function () {
|
||||
return sharp(fixtures.inputJpgWithCorruptHeader)
|
||||
.stats().then(function (stats) {
|
||||
throw new Error('Corrupt Header file');
|
||||
}).catch(function (err) {
|
||||
assert.ok(!!err);
|
||||
});
|
||||
});
|
||||
|
||||
it('File input with corrupt header fails gracefully, Stream In, Promise Out', function () {
|
||||
const pipeline = sharp();
|
||||
|
||||
fs.createReadStream(fixtures.inputJpgWithCorruptHeader).pipe(pipeline);
|
||||
|
||||
return pipeline
|
||||
.stats().then(function (stats) {
|
||||
throw new Error('Corrupt Header file');
|
||||
}).catch(function (err) {
|
||||
assert.ok(!!err);
|
||||
});
|
||||
});
|
||||
|
||||
it('Buffer input with corrupt header fails gracefully', function (done) {
|
||||
sharp(fs.readFileSync(fixtures.inputJpgWithCorruptHeader))
|
||||
.stats(function (err) {
|
||||
assert.strictEqual(true, !!err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Non-existent file in, Promise out', function (done) {
|
||||
sharp('fail').stats().then(function (stats) {
|
||||
throw new Error('Non-existent file');
|
||||
}, function (err) {
|
||||
assert.ok(!!err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user