sharp/test/fixtures/index.js
Lovell Fuller 36e636dca1 Drop support for versions of Node prior to v4.
Reduce production (sub)depedency count from 93 to 50.
Modernise dev tooling, e.g. use nyc, replace jshint with semistandard.
Make 'npm test' command consistent across platforms.
2016-11-02 09:25:20 +00:00

177 lines
8.2 KiB
JavaScript

'use strict';
const path = require('path');
const sharp = require('../../index');
const maxColourDistance = require('../../build/Release/sharp')._maxColourDistance;
// Helpers
const getPath = function (filename) {
return path.join(__dirname, filename);
};
// Generates a 64-bit-as-binary-string image fingerprint
// Based on the dHash gradient method - see http://www.hackerfactor.com/blog/index.php?/archives/529-Kind-of-Like-That.html
const fingerprint = function (image, callback) {
sharp(image)
.greyscale()
.normalise()
.resize(9, 8)
.ignoreAspectRatio()
.raw()
.toBuffer(function (err, data) {
if (err) {
callback(err);
} else {
let fingerprint = '';
for (let col = 0; col < 8; col++) {
for (let row = 0; row < 8; row++) {
const left = data[row * 8 + col];
const right = data[row * 8 + col + 1];
fingerprint = fingerprint + (left < right ? '1' : '0');
}
}
callback(null, fingerprint);
}
});
};
module.exports = {
inputJpgWithLandscapeExif1: getPath('Landscape_1.jpg'), // https://github.com/recurser/exif-orientation-examples
inputJpgWithLandscapeExif2: getPath('Landscape_2.jpg'), // https://github.com/recurser/exif-orientation-examples
inputJpgWithLandscapeExif3: getPath('Landscape_3.jpg'), // https://github.com/recurser/exif-orientation-examples
inputJpgWithLandscapeExif4: getPath('Landscape_4.jpg'), // https://github.com/recurser/exif-orientation-examples
inputJpgWithLandscapeExif5: getPath('Landscape_5.jpg'), // https://github.com/recurser/exif-orientation-examples
inputJpgWithLandscapeExif6: getPath('Landscape_6.jpg'), // https://github.com/recurser/exif-orientation-examples
inputJpgWithLandscapeExif7: getPath('Landscape_7.jpg'), // https://github.com/recurser/exif-orientation-examples
inputJpgWithLandscapeExif8: getPath('Landscape_8.jpg'), // https://github.com/recurser/exif-orientation-examples
inputJpgWithPortraitExif1: getPath('Portrait_1.jpg'), // https://github.com/recurser/exif-orientation-examples
inputJpgWithPortraitExif2: getPath('Portrait_2.jpg'), // https://github.com/recurser/exif-orientation-examples
inputJpgWithPortraitExif3: getPath('Portrait_3.jpg'), // https://github.com/recurser/exif-orientation-examples
inputJpgWithPortraitExif4: getPath('Portrait_4.jpg'), // https://github.com/recurser/exif-orientation-examples
inputJpgWithPortraitExif5: getPath('Portrait_5.jpg'), // https://github.com/recurser/exif-orientation-examples
inputJpgWithPortraitExif6: getPath('Portrait_6.jpg'), // https://github.com/recurser/exif-orientation-examples
inputJpgWithPortraitExif7: getPath('Portrait_7.jpg'), // https://github.com/recurser/exif-orientation-examples
inputJpgWithPortraitExif8: getPath('Portrait_8.jpg'), // https://github.com/recurser/exif-orientation-examples
inputJpg: getPath('2569067123_aca715a2ee_o.jpg'), // http://www.flickr.com/photos/grizdave/2569067123/
inputJpgWithExif: getPath('Landscape_8.jpg'), // https://github.com/recurser/exif-orientation-examples/blob/master/Landscape_8.jpg
inputJpgWithExifMirroring: getPath('Landscape_5.jpg'), // https://github.com/recurser/exif-orientation-examples/blob/master/Landscape_5.jpg
inputJpgWithGammaHoliness: getPath('gamma_dalai_lama_gray.jpg'), // http://www.4p8.com/eric.brasseur/gamma.html
inputJpgWithCmykProfile: getPath('Channel_digital_image_CMYK_color.jpg'), // http://en.wikipedia.org/wiki/File:Channel_digital_image_CMYK_color.jpg
inputJpgWithCmykNoProfile: getPath('Channel_digital_image_CMYK_color_no_profile.jpg'),
inputJpgWithCorruptHeader: getPath('corrupt-header.jpg'),
inputJpgWithLowContrast: getPath('low-contrast.jpg'), // http://www.flickr.com/photos/grizdave/2569067123/
inputJpgLarge: getPath('giant-image.jpg'),
inputPng: getPath('50020484-00001.png'), // http://c.searspartsdirect.com/lis_png/PLDM/50020484-00001.png
inputPngWithTransparency: getPath('blackbug.png'), // public domain
inputPngWithGreyAlpha: getPath('grey-8bit-alpha.png'),
inputPngWithOneColor: getPath('2x2_fdcce6.png'),
inputPngWithTransparency16bit: getPath('tbgn2c16.png'), // http://www.schaik.com/pngsuite/tbgn2c16.png
inputPngOverlayLayer0: getPath('alpha-layer-0-background.png'),
inputPngOverlayLayer1: getPath('alpha-layer-1-fill.png'),
inputPngOverlayLayer2: getPath('alpha-layer-2-ink.png'),
inputPngOverlayLayer1LowAlpha: getPath('alpha-layer-1-fill-low-alpha.png'),
inputPngOverlayLayer2LowAlpha: getPath('alpha-layer-2-ink-low-alpha.png'),
inputPngAlphaPremultiplicationSmall: getPath('alpha-premultiply-1024x768-paper.png'),
inputPngAlphaPremultiplicationLarge: getPath('alpha-premultiply-2048x1536-paper.png'),
inputPngBooleanNoAlpha: getPath('bandbool.png'),
inputPngTestJoinChannel: getPath('testJoinChannel.png'),
inputWebP: getPath('4.webp'), // http://www.gstatic.com/webp/gallery/4.webp
inputWebPWithTransparency: getPath('5_webp_a.webp'), // http://www.gstatic.com/webp/gallery3/5_webp_a.webp
inputTiff: getPath('G31D.TIF'), // http://www.fileformat.info/format/tiff/sample/e6c9a6e5253348f4aef6d17b534360ab/index.htm
inputGif: getPath('Crash_test.gif'), // http://upload.wikimedia.org/wikipedia/commons/e/e3/Crash_test.gif
inputGifGreyPlusAlpha: getPath('grey-plus-alpha.gif'), // http://i.imgur.com/gZ5jlmE.gif
inputSvg: getPath('check.svg'), // http://dev.w3.org/SVG/tools/svgweb/samples/svg-files/check.svg
inputSvgWithEmbeddedImages: getPath('struct-image-04-t.svg'), // https://dev.w3.org/SVG/profiles/1.2T/test/svg/struct-image-04-t.svg
inputJPGBig: getPath('flowers.jpeg'),
inputPngStripesV: getPath('stripesV.png'),
inputPngStripesH: getPath('stripesH.png'),
inputJpgBooleanTest: getPath('booleanTest.jpg'),
inputV: getPath('vfile.v'),
outputJpg: getPath('output.jpg'),
outputPng: getPath('output.png'),
outputWebP: getPath('output.webp'),
outputV: getPath('output.v'),
outputZoinks: getPath('output.zoinks'), // an 'unknown' file extension
// Path for tests requiring human inspection
path: getPath,
// Path for expected output images
expected: function (filename) {
return getPath(path.join('expected', filename));
},
// Verify similarity of expected vs actual images via fingerprint
// Specify distance threshold using `options={threshold: 42}`, default
// `threshold` is 5;
assertSimilar: function (expectedImage, actualImage, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
if (typeof options === 'undefined' && options === null) {
options = {};
}
if (options.threshold === null || typeof options.threshold === 'undefined') {
options.threshold = 5; // ~7% threshold
}
if (typeof options.threshold !== 'number') {
throw new TypeError('`options.threshold` must be a number');
}
if (typeof callback !== 'function') {
throw new TypeError('`callback` must be a function');
}
fingerprint(expectedImage, function (err, expectedFingerprint) {
if (err) return callback(err);
fingerprint(actualImage, function (err, actualFingerprint) {
if (err) return callback(err);
let distance = 0;
for (let i = 0; i < 64; i++) {
if (expectedFingerprint[i] !== actualFingerprint[i]) {
distance++;
}
}
if (distance > options.threshold) {
return callback(new Error('Expected maximum similarity distance: ' + options.threshold + '. Actual: ' + distance + '.'));
}
callback();
});
});
},
assertMaxColourDistance: function (actualImagePath, expectedImagePath, acceptedDistance) {
if (typeof actualImagePath !== 'string') {
throw new TypeError('`actualImagePath` must be a string; got ' + actualImagePath);
}
if (typeof expectedImagePath !== 'string') {
throw new TypeError('`expectedImagePath` must be a string; got ' + expectedImagePath);
}
if (typeof acceptedDistance !== 'number') {
// Default threshold
acceptedDistance = 1;
}
const distance = maxColourDistance(actualImagePath, expectedImagePath);
if (distance > acceptedDistance) {
throw new Error('Expected maximum absolute distance of ' + acceptedDistance + ', actual ' + distance);
}
}
};