mirror of
https://github.com/lovell/sharp.git
synced 2026-02-04 21:56:18 +01:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
531a0402f7 | ||
|
|
cb10f9a9c8 | ||
|
|
c808139b02 | ||
|
|
e0d58266be | ||
|
|
1b7c5816fc | ||
|
|
b224874332 | ||
|
|
ef61da3051 | ||
|
|
f214269aa1 | ||
|
|
6bc2ea8dc7 | ||
|
|
71fb839e2b | ||
|
|
8c9c070caf |
@@ -13,3 +13,4 @@ mkdocs.yml
|
||||
lib
|
||||
include
|
||||
packaging
|
||||
preinstall.sh
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
'CLANG_CXX_LIBRARY': 'libc++',
|
||||
'MACOSX_DEPLOYMENT_TARGET': '10.7',
|
||||
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
|
||||
'GCC_ENABLE_CPP_RTTI': 'YES',
|
||||
'OTHER_CPLUSPLUSFLAGS': [
|
||||
'-fexceptions',
|
||||
'-Wall',
|
||||
|
||||
@@ -12,6 +12,9 @@ var tmp = require('os').tmpdir();
|
||||
|
||||
var distBaseUrl = 'https://dl.bintray.com/lovell/sharp/';
|
||||
|
||||
// Use NPM-provided environment variable where available, falling back to require-based method for Electron
|
||||
var minimumLibvipsVersion = process.env.npm_package_config_libvips || require('./package.json').config.libvips;
|
||||
|
||||
var vipsHeaderPath = path.join(__dirname, 'include', 'vips', 'vips.h');
|
||||
|
||||
// -- Helpers
|
||||
@@ -75,7 +78,7 @@ module.exports.download_vips = function() {
|
||||
}
|
||||
// Arch/platform-specific .tar.gz
|
||||
var platform = (process.arch === 'arm') ? 'arm' : process.platform.substr(0, 3);
|
||||
var tarFilename = ['libvips', process.env.npm_package_config_libvips, platform].join('-') + '.tar.gz';
|
||||
var tarFilename = ['libvips', minimumLibvipsVersion, platform].join('-') + '.tar.gz';
|
||||
var tarPath = path.join(__dirname, 'packaging', tarFilename);
|
||||
if (isFile(tarPath)) {
|
||||
unpack(tarPath);
|
||||
@@ -114,13 +117,13 @@ module.exports.use_global_vips = function() {
|
||||
if (globalVipsVersion) {
|
||||
useGlobalVips = semver.gte(
|
||||
globalVipsVersion,
|
||||
process.env.npm_package_config_libvips
|
||||
minimumLibvipsVersion
|
||||
);
|
||||
}
|
||||
if (process.platform === 'darwin' && !useGlobalVips) {
|
||||
if (globalVipsVersion) {
|
||||
error(
|
||||
'Found libvips ' + globalVipsVersion + ' but require ' + process.env.npm_package_config_libvips +
|
||||
'Found libvips ' + globalVipsVersion + ' but require ' + minimumLibvipsVersion +
|
||||
'\nPlease upgrade libvips by running: brew update && brew upgrade'
|
||||
);
|
||||
} else {
|
||||
|
||||
@@ -113,7 +113,8 @@ This will reduce memory usage and can improve performance on some systems.
|
||||
|
||||
Do not process input images where the number of pixels (width * height) exceeds this limit.
|
||||
|
||||
`pixels` is the integral Number of pixels, with a value between 1 and the default 268402689 (0x3FFF * 0x3FFF).
|
||||
`pixels` is either an integral Number of pixels, with a value between 1 and the default 268402689 (0x3FFF * 0x3FFF) or
|
||||
a boolean. `false` will disable checking while `true` will revert to the default limit.
|
||||
|
||||
### Resizing
|
||||
|
||||
@@ -526,14 +527,17 @@ The default behaviour, when `withMetadata` is not used, is to strip all metadata
|
||||
|
||||
#### tile(options)
|
||||
|
||||
The size, overlap and directory layout to use when generating square Deep Zoom image pyramid tiles.
|
||||
The size, overlap, container and directory layout to use when generating square Deep Zoom image pyramid tiles.
|
||||
|
||||
`options` is an Object with one or more of the following attributes:
|
||||
|
||||
* `size` is an integral Number between 1 and 8192. The default value is 256 pixels.
|
||||
* `overlap` is an integral Number between 0 and 8192. The default value is 0 pixels.
|
||||
* `container` is a String, with value `fs` or `zip`. The default value is `fs`.
|
||||
* `layout` is a String, with value `dz`, `zoomify` or `google`. The default value is `dz`.
|
||||
|
||||
You can also use the file extension .zip or .szi to write to a ZIP container instead of the filesystem.
|
||||
|
||||
```javascript
|
||||
sharp('input.tiff')
|
||||
.tile({
|
||||
|
||||
@@ -4,6 +4,30 @@
|
||||
|
||||
Requires libvips v8.2.3
|
||||
|
||||
#### v0.14.1 - 16<sup>th</sup> April 2016
|
||||
|
||||
* Allow removal of limitation on input pixel count via limitInputPixels. Use with care.
|
||||
[#250](https://github.com/lovell/sharp/issues/250)
|
||||
[#316](https://github.com/lovell/sharp/pull/316)
|
||||
[@anandthakker](https://github.com/anandthakker)
|
||||
[@kentongray](https://github.com/kentongray)
|
||||
|
||||
* Use final output image for metadata passed to callback.
|
||||
[#399](https://github.com/lovell/sharp/pull/399)
|
||||
[@salzhrani](https://github.com/salzhrani)
|
||||
|
||||
* Add support for writing tiled images to a zip container.
|
||||
[#402](https://github.com/lovell/sharp/pull/402)
|
||||
[@felixbuenemann](https://github.com/felixbuenemann)
|
||||
|
||||
* Allow use of embed with 1 and 2 channel images.
|
||||
[#411](https://github.com/lovell/sharp/issues/411)
|
||||
[@janaz](https://github.com/janaz)
|
||||
|
||||
* Improve Electron compatibility by allowing node-gyp rebuilds without npm.
|
||||
[#412](https://github.com/lovell/sharp/issues/412)
|
||||
[@nouh](https://github.com/nouh)
|
||||
|
||||
#### v0.14.0 - 2<sup>nd</sup> April 2016
|
||||
|
||||
* Add ability to extend (pad) the edges of an image.
|
||||
|
||||
@@ -52,9 +52,15 @@ For Linux-based operating systems such as Alpine that use musl libc,
|
||||
the smaller stack size means libvips' cache should be disabled
|
||||
via `sharp.cache(false)` to avoid a stack overflow.
|
||||
|
||||
Beware of Linux OS upgrades that introduce v5.1+ of the `g++` compiler due to
|
||||
[changes](https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html)
|
||||
in the C++11 ABI.
|
||||
This module assumes the previous behaviour, which can be enforced by setting the
|
||||
`_GLIBCXX_USE_CXX11_ABI=0` environment variable at libvips' compile time.
|
||||
|
||||
### Mac OS
|
||||
|
||||
[](https://travis-ci.org/lovell/sharp-osx-ci)
|
||||
[](https://travis-ci.org/lovell/sharp)
|
||||
|
||||
libvips must be installed before `npm install` is run.
|
||||
This can be achieved via homebrew:
|
||||
|
||||
19
index.js
19
index.js
@@ -660,6 +660,14 @@ Sharp.prototype.tile = function(tile) {
|
||||
throw new Error('Invalid tile overlap (0 to 8192) ' + tile.overlap);
|
||||
}
|
||||
}
|
||||
// Container
|
||||
if (isDefined(tile.container)) {
|
||||
if (isString(tile.container) && contains(tile.container, ['fs', 'zip'])) {
|
||||
this.options.tileContainer = tile.container;
|
||||
} else {
|
||||
throw new Error('Invalid tile container ' + tile.container);
|
||||
}
|
||||
}
|
||||
// Layout
|
||||
if (isDefined(tile.layout)) {
|
||||
if (isString(tile.layout) && contains(tile.layout, ['dz', 'google', 'zoomify'])) {
|
||||
@@ -722,10 +730,17 @@ Sharp.prototype.resize = function(width, height) {
|
||||
|
||||
/*
|
||||
Limit the total number of pixels for input images
|
||||
Assumes the image dimensions contained in the file header can be trusted
|
||||
Assumes the image dimensions contained in the file header can be trusted.
|
||||
Alternatively can use boolean to disable or reset to default (maximum pixels)
|
||||
*/
|
||||
Sharp.prototype.limitInputPixels = function(limit) {
|
||||
if (typeof limit === 'number' && !Number.isNaN(limit) && limit % 1 === 0 && limit > 0) {
|
||||
//if we pass in false we represent the integer as 0 to disable
|
||||
if(limit === false) {
|
||||
limit = 0;
|
||||
} else if(limit === true) {
|
||||
limit = maximum.pixels;
|
||||
}
|
||||
if (typeof limit === 'number' && !Number.isNaN(limit) && limit % 1 === 0 && limit >= 0) {
|
||||
this.options.limitInputPixels = limit;
|
||||
} else {
|
||||
throw new Error('Invalid pixel limit (1 to ' + maximum.pixels + ') ' + limit);
|
||||
|
||||
18
package.json
18
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sharp",
|
||||
"version": "0.14.0",
|
||||
"version": "0.14.1",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"contributors": [
|
||||
"Pierre Inglebert <pierre.inglebert@gmail.com>",
|
||||
@@ -19,13 +19,16 @@
|
||||
"Bernhard K. Weisshuhn <bkw@codingforce.com>",
|
||||
"Chris Riley <criley@primedia.com>",
|
||||
"David Carley <dacarley@gmail.com>",
|
||||
"John Tobin <john@limelightmobileinc.com>"
|
||||
"John Tobin <john@limelightmobileinc.com>",
|
||||
"Kenton Gray <kentongray@gmail.com>",
|
||||
"Felix Bünemann <Felix.Buenemann@gmail.com>",
|
||||
"Samy Al Zahrani <samyalzahrany@gmail.com>"
|
||||
],
|
||||
"description": "High performance Node.js module to resize JPEG, PNG, WebP and TIFF images using the libvips library",
|
||||
"scripts": {
|
||||
"clean": "rm -rf node_modules/ build/ include/ lib/ coverage/ test/fixtures/output.*",
|
||||
"test": "VIPS_WARNING=0 node ./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha -- --slow=5000 --timeout=30000 ./test/unit/*.js",
|
||||
"test-win": "node ./node_modules/mocha/bin/mocha --slow=5000 --timeout=30000 ./test/unit/*.js",
|
||||
"test-win": "node ./node_modules/mocha/bin/mocha --slow=5000 --timeout=60000 ./test/unit/*.js",
|
||||
"test-leak": "./test/leak/leak.sh",
|
||||
"test-packaging": "./packaging/test.sh",
|
||||
"test-clean": "rm -rf coverage/ test/fixtures/output.* && npm install && npm test"
|
||||
@@ -48,24 +51,25 @@
|
||||
"vips"
|
||||
],
|
||||
"dependencies": {
|
||||
"bluebird": "^3.3.4",
|
||||
"bluebird": "^3.3.5",
|
||||
"color": "^0.11.1",
|
||||
"nan": "^2.2.1",
|
||||
"semver": "^5.1.0",
|
||||
"request": "^2.69.0",
|
||||
"request": "^2.71.0",
|
||||
"tar": "^2.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"async": "^1.5.2",
|
||||
"bufferutil": "^1.2.1",
|
||||
"coveralls": "^2.11.9",
|
||||
"exif-reader": "^1.0.0",
|
||||
"icc": "^0.0.2",
|
||||
"istanbul": "^0.4.2",
|
||||
"istanbul": "^0.4.3",
|
||||
"mocha": "^2.4.5",
|
||||
"mocha-jshint": "^2.3.1",
|
||||
"node-cpplint": "^0.4.0",
|
||||
"rimraf": "^2.5.2",
|
||||
"bufferutil": "^1.2.1"
|
||||
"unzip": "^0.1.11"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"config": {
|
||||
|
||||
@@ -52,6 +52,9 @@ namespace sharp {
|
||||
bool IsDz(std::string const &str) {
|
||||
return EndsWith(str, ".dzi") || EndsWith(str, ".DZI");
|
||||
}
|
||||
bool IsDzZip(std::string const &str) {
|
||||
return EndsWith(str, ".zip") || EndsWith(str, ".ZIP") || EndsWith(str, ".szi") || EndsWith(str, ".SZI");
|
||||
}
|
||||
|
||||
/*
|
||||
Provide a string identifier for the given image type.
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace sharp {
|
||||
bool IsWebp(std::string const &str);
|
||||
bool IsTiff(std::string const &str);
|
||||
bool IsDz(std::string const &str);
|
||||
bool IsDzZip(std::string const &str);
|
||||
|
||||
/*
|
||||
Provide a string identifier for the given image type.
|
||||
|
||||
@@ -65,6 +65,7 @@ using sharp::IsPng;
|
||||
using sharp::IsWebp;
|
||||
using sharp::IsTiff;
|
||||
using sharp::IsDz;
|
||||
using sharp::IsDzZip;
|
||||
using sharp::FreeCallback;
|
||||
using sharp::CalculateCrop;
|
||||
using sharp::counterProcess;
|
||||
@@ -103,14 +104,19 @@ class PipelineWorker : public AsyncWorker {
|
||||
// From buffer
|
||||
if (baton->rawWidth > 0 && baton->rawHeight > 0 && baton->rawChannels > 0) {
|
||||
// Raw, uncompressed pixel data
|
||||
image = VImage::new_from_memory(baton->bufferIn, baton->bufferInLength,
|
||||
baton->rawWidth, baton->rawHeight, baton->rawChannels, VIPS_FORMAT_UCHAR);
|
||||
if (baton->rawChannels < 3) {
|
||||
image.get_image()->Type = VIPS_INTERPRETATION_B_W;
|
||||
} else {
|
||||
image.get_image()->Type = VIPS_INTERPRETATION_sRGB;
|
||||
try {
|
||||
image = VImage::new_from_memory(baton->bufferIn, baton->bufferInLength,
|
||||
baton->rawWidth, baton->rawHeight, baton->rawChannels, VIPS_FORMAT_UCHAR);
|
||||
if (baton->rawChannels < 3) {
|
||||
image.get_image()->Type = VIPS_INTERPRETATION_B_W;
|
||||
} else {
|
||||
image.get_image()->Type = VIPS_INTERPRETATION_sRGB;
|
||||
}
|
||||
inputImageType = ImageType::RAW;
|
||||
} catch(VError const &err) {
|
||||
(baton->err).append(err.what());
|
||||
inputImageType = ImageType::UNKNOWN;
|
||||
}
|
||||
inputImageType = ImageType::RAW;
|
||||
} else {
|
||||
// Compressed data
|
||||
inputImageType = DetermineImageType(baton->bufferIn, baton->bufferInLength);
|
||||
@@ -158,7 +164,8 @@ class PipelineWorker : public AsyncWorker {
|
||||
}
|
||||
|
||||
// Limit input images to a given number of pixels, where pixels = width * height
|
||||
if (image.width() * image.height() > baton->limitInputPixels) {
|
||||
// Ignore if 0
|
||||
if (baton->limitInputPixels > 0 && image.width() * image.height() > baton->limitInputPixels) {
|
||||
(baton->err).append("Input image exceeds pixel limit");
|
||||
return Error();
|
||||
}
|
||||
@@ -489,11 +496,21 @@ class PipelineWorker : public AsyncWorker {
|
||||
// Scale up 8-bit values to match 16-bit input image
|
||||
double multiplier = (image.interpretation() == VIPS_INTERPRETATION_RGB16) ? 256.0 : 1.0;
|
||||
// Create background colour
|
||||
std::vector<double> background {
|
||||
baton->background[0] * multiplier,
|
||||
baton->background[1] * multiplier,
|
||||
baton->background[2] * multiplier
|
||||
};
|
||||
std::vector<double> background;
|
||||
if (image.bands() > 2) {
|
||||
background = {
|
||||
multiplier * baton->background[0],
|
||||
multiplier * baton->background[1],
|
||||
multiplier * baton->background[2]
|
||||
};
|
||||
} else {
|
||||
// Convert sRGB to greyscale
|
||||
background = { multiplier * (
|
||||
0.2126 * baton->background[0] +
|
||||
0.7152 * baton->background[1] +
|
||||
0.0722 * baton->background[2]
|
||||
)};
|
||||
}
|
||||
// Add alpha channel to background colour
|
||||
if (baton->background[3] < 255.0 || HasAlpha(image)) {
|
||||
background.push_back(baton->background[3] * multiplier);
|
||||
@@ -655,7 +672,8 @@ class PipelineWorker : public AsyncWorker {
|
||||
|
||||
// Number of channels used in output image
|
||||
baton->channels = image.bands();
|
||||
|
||||
baton->width = image.width();
|
||||
baton->height = image.height();
|
||||
// Output
|
||||
if (baton->fileOut == "") {
|
||||
// Buffer output
|
||||
@@ -736,7 +754,8 @@ class PipelineWorker : public AsyncWorker {
|
||||
bool isWebp = IsWebp(baton->fileOut);
|
||||
bool isTiff = IsTiff(baton->fileOut);
|
||||
bool isDz = IsDz(baton->fileOut);
|
||||
bool matchInput = baton->formatOut == "input" && !(isJpeg || isPng || isWebp || isTiff || isDz);
|
||||
bool isDzZip = IsDzZip(baton->fileOut);
|
||||
bool matchInput = baton->formatOut == "input" && !(isJpeg || isPng || isWebp || isTiff || isDz || isDzZip);
|
||||
if (baton->formatOut == "jpeg" || isJpeg || (matchInput && inputImageType == ImageType::JPEG)) {
|
||||
// Write JPEG to file
|
||||
image.jpegsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
||||
@@ -777,12 +796,16 @@ class PipelineWorker : public AsyncWorker {
|
||||
);
|
||||
baton->formatOut = "tiff";
|
||||
baton->channels = std::min(baton->channels, 3);
|
||||
} else if (baton->formatOut == "dz" || IsDz(baton->fileOut)) {
|
||||
} else if (baton->formatOut == "dz" || isDz || isDzZip) {
|
||||
if (isDzZip) {
|
||||
baton->tileContainer = VIPS_FOREIGN_DZ_CONTAINER_ZIP;
|
||||
}
|
||||
// Write DZ to file
|
||||
image.dzsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
||||
->set("strip", !baton->withMetadata)
|
||||
->set("tile_size", baton->tileSize)
|
||||
->set("overlap", baton->tileOverlap)
|
||||
->set("container", baton->tileContainer)
|
||||
->set("layout", baton->tileLayout)
|
||||
);
|
||||
baton->formatOut = "dz";
|
||||
@@ -1051,6 +1074,12 @@ NAN_METHOD(pipeline) {
|
||||
// Tile output
|
||||
baton->tileSize = attrAs<int32_t>(options, "tileSize");
|
||||
baton->tileOverlap = attrAs<int32_t>(options, "tileOverlap");
|
||||
std::string tileContainer = attrAsStr(options, "tileContainer");
|
||||
if (tileContainer == "zip") {
|
||||
baton->tileContainer = VIPS_FOREIGN_DZ_CONTAINER_ZIP;
|
||||
} else {
|
||||
baton->tileContainer = VIPS_FOREIGN_DZ_CONTAINER_FS;
|
||||
}
|
||||
std::string tileLayout = attrAsStr(options, "tileLayout");
|
||||
if (tileLayout == "google") {
|
||||
baton->tileLayout = VIPS_FOREIGN_DZ_LAYOUT_GOOGLE;
|
||||
|
||||
@@ -81,6 +81,7 @@ struct PipelineBaton {
|
||||
int withMetadataOrientation;
|
||||
int tileSize;
|
||||
int tileOverlap;
|
||||
VipsForeignDzContainer tileContainer;
|
||||
VipsForeignDzLayout tileLayout;
|
||||
|
||||
PipelineBaton():
|
||||
@@ -130,6 +131,7 @@ struct PipelineBaton {
|
||||
withMetadataOrientation(-1),
|
||||
tileSize(256),
|
||||
tileOverlap(0),
|
||||
tileContainer(VIPS_FOREIGN_DZ_CONTAINER_FS),
|
||||
tileLayout(VIPS_FOREIGN_DZ_LAYOUT_DZ) {
|
||||
background[0] = 0.0;
|
||||
background[1] = 0.0;
|
||||
|
||||
BIN
test/fixtures/expected/embed-2channel.png
vendored
Normal file
BIN
test/fixtures/expected/embed-2channel.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 703 B |
BIN
test/fixtures/flowers.jpeg
vendored
Normal file
BIN
test/fixtures/flowers.jpeg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 83 KiB |
BIN
test/fixtures/giant-image.jpg
vendored
Normal file
BIN
test/fixtures/giant-image.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
3
test/fixtures/index.js
vendored
3
test/fixtures/index.js
vendored
@@ -66,6 +66,7 @@ module.exports = {
|
||||
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
|
||||
@@ -89,6 +90,8 @@ module.exports = {
|
||||
|
||||
inputSvs: getPath('CMU-1-Small-Region.svs'), // http://openslide.cs.cmu.edu/download/openslide-testdata/Aperio/CMU-1-Small-Region.svs
|
||||
|
||||
inputJPGBig: getPath('flowers.jpeg'),
|
||||
|
||||
outputJpg: getPath('output.jpg'),
|
||||
outputPng: getPath('output.png'),
|
||||
outputWebP: getPath('output.webp'),
|
||||
|
||||
@@ -53,7 +53,7 @@ describe('Alpha transparency', function() {
|
||||
assert.strictEqual(true, info.size > 0);
|
||||
assert.strictEqual(32, info.width);
|
||||
assert.strictEqual(32, info.height);
|
||||
fixtures.assertSimilar(fixtures.expected('flatten-rgb16-orange.jpg'), data, done);
|
||||
fixtures.assertSimilar(fixtures.expected('flatten-rgb16-orange.jpg'), data, { threshold: 6 }, done);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -88,6 +88,22 @@ describe('Embed', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('PNG with 2 channels', function(done) {
|
||||
sharp(fixtures.inputPngWithGreyAlpha)
|
||||
.resize(32, 16)
|
||||
.embed()
|
||||
.background({r: 0, g: 0, b: 0, a: 0})
|
||||
.toBuffer(function(err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(true, data.length > 0);
|
||||
assert.strictEqual('png', info.format);
|
||||
assert.strictEqual(32, info.width);
|
||||
assert.strictEqual(16, info.height);
|
||||
assert.strictEqual(4, info.channels);
|
||||
fixtures.assertSimilar(fixtures.expected('embed-2channel.png'), data, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('Enlarge and embed', function(done) {
|
||||
sharp(fixtures.inputPngWithOneColor)
|
||||
.embed()
|
||||
|
||||
@@ -38,7 +38,7 @@ describe('Gamma correction', function() {
|
||||
assert.strictEqual('jpeg', info.format);
|
||||
assert.strictEqual(129, info.width);
|
||||
assert.strictEqual(111, info.height);
|
||||
fixtures.assertSimilar(fixtures.expected('gamma-3.0.jpg'), data, done);
|
||||
fixtures.assertSimilar(fixtures.expected('gamma-3.0.jpg'), data, { threshold: 6 }, done);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -49,7 +49,7 @@ describe('Gamma correction', function() {
|
||||
.toBuffer(function(err, data, info) {
|
||||
assert.strictEqual('png', info.format);
|
||||
assert.strictEqual(320, info.width);
|
||||
fixtures.assertSimilar(fixtures.expected('gamma-alpha.jpg'), data, done);
|
||||
fixtures.assertSimilar(fixtures.expected('gamma-alpha.jpg'), data, { threshold: 11 }, done);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -876,6 +876,25 @@ describe('Input/output', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('Disabling limit works', function(done) {
|
||||
sharp(fixtures.inputJpgLarge)
|
||||
.limitInputPixels(false)
|
||||
.resize(2)
|
||||
.toBuffer(function(err) {
|
||||
assert.strictEqual(true, !err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Enabling default limit works and fails with a large image', function(done) {
|
||||
sharp(fixtures.inputJpgLarge)
|
||||
.limitInputPixels(true)
|
||||
.toBuffer(function(err) {
|
||||
assert.strictEqual(true, !!err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Smaller than input fails', function(done) {
|
||||
sharp(fixtures.inputJpg).metadata(function(err, metadata) {
|
||||
if (err) throw err;
|
||||
@@ -1012,4 +1031,32 @@ describe('Input/output', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('Info event data', function(done) {
|
||||
var readable = fs.createReadStream(fixtures.inputJPGBig);
|
||||
var inPipeline = sharp()
|
||||
.resize(840)
|
||||
.raw()
|
||||
.on('info', function(info) {
|
||||
assert.strictEqual(840, info.width);
|
||||
assert.strictEqual(472, info.height);
|
||||
assert.strictEqual(3, info.channels);
|
||||
});
|
||||
var badPipeline = sharp(null, {raw: {width: 840, height: 473, channels: 3}})
|
||||
.toFormat('jpeg')
|
||||
.toBuffer(function(err, data, info) {
|
||||
assert.strictEqual(err.message.indexOf('memory area too small') > 0, true);
|
||||
readable = fs.createReadStream(fixtures.inputJPGBig);
|
||||
var goodPipeline = sharp(null, {raw: {width: 840, height: 472, channels: 3}})
|
||||
.toFormat('jpeg')
|
||||
.toBuffer(function(err, data, info) {
|
||||
if (err) throw err;
|
||||
done();
|
||||
});
|
||||
inPipeline = sharp()
|
||||
.resize(840)
|
||||
.raw();
|
||||
readable.pipe(inPipeline).pipe(goodPipeline);
|
||||
});
|
||||
readable.pipe(inPipeline).pipe(badPipeline);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ var assert = require('assert');
|
||||
|
||||
var async = require('async');
|
||||
var rimraf = require('rimraf');
|
||||
var unzip = require('unzip');
|
||||
|
||||
var sharp = require('../../index');
|
||||
var fixtures = require('../fixtures');
|
||||
@@ -88,6 +89,26 @@ describe('Tile', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('Valid container values pass', function() {
|
||||
['fs', 'zip'].forEach(function(container) {
|
||||
assert.doesNotThrow(function() {
|
||||
sharp().tile({
|
||||
container: container
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Invalid container values fail', function() {
|
||||
['zoinks', 1].forEach(function(container) {
|
||||
assert.throws(function() {
|
||||
sharp().tile({
|
||||
container: container
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Valid layout values pass', function() {
|
||||
['dz', 'google', 'zoomify'].forEach(function(layout) {
|
||||
assert.doesNotThrow(function() {
|
||||
@@ -190,6 +211,58 @@ describe('Tile', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('Write to ZIP container using file extension', function(done) {
|
||||
var container = fixtures.path('output.dz.container.zip');
|
||||
var extractTo = fixtures.path('output.dz.container');
|
||||
var directory = path.join(extractTo, 'output.dz.container_files');
|
||||
rimraf(directory, function() {
|
||||
sharp(fixtures.inputJpg)
|
||||
.toFile(container, function(err, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual('dz', info.format);
|
||||
fs.stat(container, function(err, stat) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(true, stat.isFile());
|
||||
assert.strictEqual(true, stat.size > 0);
|
||||
fs.createReadStream(container)
|
||||
.pipe(unzip.Extract({path: path.dirname(extractTo)}))
|
||||
.on('error', function(err) { throw err; })
|
||||
.on('close', function() {
|
||||
assertDeepZoomTiles(directory, 256, 13, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Write to ZIP container using container tile option', function(done) {
|
||||
var container = fixtures.path('output.dz.containeropt.zip');
|
||||
var extractTo = fixtures.path('output.dz.containeropt');
|
||||
var directory = path.join(extractTo, 'output.dz.containeropt_files');
|
||||
rimraf(directory, function() {
|
||||
sharp(fixtures.inputJpg)
|
||||
.tile({
|
||||
container: 'zip'
|
||||
})
|
||||
.toFile(fixtures.path('output.dz.containeropt.dzi'), function(err, info) {
|
||||
// Vips overrides .dzi extension to .zip used by container var below
|
||||
if (err) throw err;
|
||||
assert.strictEqual('dz', info.format);
|
||||
fs.stat(container, function(err, stat) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(true, stat.isFile());
|
||||
assert.strictEqual(true, stat.size > 0);
|
||||
fs.createReadStream(container)
|
||||
.pipe(unzip.Extract({path: path.dirname(extractTo)}))
|
||||
.on('error', function(err) { throw err; })
|
||||
.on('close', function() {
|
||||
assertDeepZoomTiles(directory, 256, 13, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user