mirror of
https://github.com/lovell/sharp.git
synced 2026-02-06 14:46:16 +01:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ca2f009f4 | ||
|
|
a900c28f7c | ||
|
|
77bbbb9715 | ||
|
|
88753a6333 | ||
|
|
bcd82f4893 | ||
|
|
749dc61f85 | ||
|
|
c7ccf6801d | ||
|
|
1565522ecc | ||
|
|
a44df2f533 | ||
|
|
317510746f | ||
|
|
ef54e327b7 | ||
|
|
d8d0158774 | ||
|
|
4d75f27a25 | ||
|
|
f89e9d726d | ||
|
|
5194b37460 | ||
|
|
ab7408c96f |
@@ -2,7 +2,7 @@
|
|||||||
"strict": true,
|
"strict": true,
|
||||||
"node": true,
|
"node": true,
|
||||||
"maxparams": 4,
|
"maxparams": 4,
|
||||||
"maxcomplexity": 11,
|
"maxcomplexity": 13,
|
||||||
"globals": {
|
"globals": {
|
||||||
"describe": true,
|
"describe": true,
|
||||||
"it": true
|
"it": true
|
||||||
|
|||||||
58
README.md
58
README.md
@@ -31,8 +31,9 @@ This module is powered by the blazingly fast [libvips](https://github.com/jcupit
|
|||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
* Node.js v0.10+
|
* Node.js v0.10+ or io.js
|
||||||
* [libvips](https://github.com/jcupitt/libvips) v7.40.0+ (7.42.0+ recommended)
|
* [libvips](https://github.com/jcupitt/libvips) v7.40.0+ (7.42.0+ recommended)
|
||||||
|
* C++11 compatible compiler such as gcc 4.6+ or clang 3.0+
|
||||||
|
|
||||||
To install the most suitable version of libvips on the following Operating Systems:
|
To install the most suitable version of libvips on the following Operating Systems:
|
||||||
|
|
||||||
@@ -218,23 +219,59 @@ sharp(inputBuffer)
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Runtime discovery of available formats
|
||||||
|
console.dir(sharp.format);
|
||||||
|
```
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
|
### Attributes
|
||||||
|
|
||||||
|
#### format
|
||||||
|
|
||||||
|
An Object containing nested boolean values
|
||||||
|
representing the available input and output formats/methods,
|
||||||
|
for example:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{ jpeg: { id: 'jpeg',
|
||||||
|
input: { file: true, buffer: true, stream: true },
|
||||||
|
output: { file: true, buffer: true, stream: true } },
|
||||||
|
png: { id: 'png',
|
||||||
|
input: { file: true, buffer: true, stream: true },
|
||||||
|
output: { file: true, buffer: true, stream: true } },
|
||||||
|
webp: { id: 'webp',
|
||||||
|
input: { file: true, buffer: true, stream: true },
|
||||||
|
output: { file: true, buffer: true, stream: true } },
|
||||||
|
tiff: { id: 'tiff',
|
||||||
|
input: { file: true, buffer: true, stream: true },
|
||||||
|
output: { file: true, buffer: false, stream: false } },
|
||||||
|
magick: { id: 'magick',
|
||||||
|
input: { file: true, buffer: true, stream: true },
|
||||||
|
output: { file: false, buffer: false, stream: false } },
|
||||||
|
raw: { id: 'raw',
|
||||||
|
input: { file: false, buffer: false, stream: false },
|
||||||
|
output: { file: false, buffer: true, stream: true } } }
|
||||||
|
```
|
||||||
|
|
||||||
### Input methods
|
### Input methods
|
||||||
|
|
||||||
#### sharp([input])
|
#### sharp([input])
|
||||||
|
|
||||||
Constructor to which further methods are chained. `input`, if present, can be one of:
|
Constructor to which further methods are chained. `input`, if present, can be one of:
|
||||||
|
|
||||||
* Buffer containing JPEG, PNG, WebP or TIFF image data, or
|
* Buffer containing JPEG, PNG, WebP, GIF* or TIFF image data, or
|
||||||
* String containing the filename of an image, with most major formats supported.
|
* String containing the filename of an image, with most major formats supported.
|
||||||
|
|
||||||
The object returned implements the [stream.Duplex](http://nodejs.org/api/stream.html#stream_class_stream_duplex) class.
|
The object returned implements the [stream.Duplex](http://nodejs.org/api/stream.html#stream_class_stream_duplex) class.
|
||||||
|
|
||||||
JPEG, PNG, WebP or TIFF format image data can be streamed into the object when `input` is not provided.
|
JPEG, PNG, WebP, GIF* or TIFF format image data can be streamed into the object when `input` is not provided.
|
||||||
|
|
||||||
JPEG, PNG or WebP format image data can be streamed out from this object.
|
JPEG, PNG or WebP format image data can be streamed out from this object.
|
||||||
|
|
||||||
|
\* libvips 8.0.0+ is required for Buffer/Stream input of GIF and other `magick` formats.
|
||||||
|
|
||||||
#### metadata([callback])
|
#### metadata([callback])
|
||||||
|
|
||||||
Fast access to image metadata without decoding any compressed image data.
|
Fast access to image metadata without decoding any compressed image data.
|
||||||
@@ -292,7 +329,19 @@ Possible values are `north`, `east`, `south`, `west`, `center` and `centre`. The
|
|||||||
|
|
||||||
#### max()
|
#### max()
|
||||||
|
|
||||||
Preserving aspect ratio, resize the image to the maximum `width` or `height` specified.
|
Preserving aspect ratio,
|
||||||
|
resize the image to be as large as possible
|
||||||
|
while ensuring its dimensions are less than or equal to
|
||||||
|
the `width` and `height` specified.
|
||||||
|
|
||||||
|
Both `width` and `height` must be provided via `resize` otherwise the behaviour will default to `crop`.
|
||||||
|
|
||||||
|
#### min()
|
||||||
|
|
||||||
|
Preserving aspect ratio,
|
||||||
|
resize the image to be as small as possible
|
||||||
|
while ensuring its dimensions are greater than or equal to
|
||||||
|
the `width` and `height` specified.
|
||||||
|
|
||||||
Both `width` and `height` must be provided via `resize` otherwise the behaviour will default to `crop`.
|
Both `width` and `height` must be provided via `resize` otherwise the behaviour will default to `crop`.
|
||||||
|
|
||||||
@@ -627,6 +676,7 @@ This module would never have been possible without the help and code contributio
|
|||||||
* [Amit Pitaru](https://github.com/apitaru)
|
* [Amit Pitaru](https://github.com/apitaru)
|
||||||
* [Brandon Aaron](https://github.com/brandonaaron)
|
* [Brandon Aaron](https://github.com/brandonaaron)
|
||||||
* [Andreas Lind](https://github.com/papandreou)
|
* [Andreas Lind](https://github.com/papandreou)
|
||||||
|
* [Maurus Cuelenaere](https://github.com/mcuelenaere)
|
||||||
|
|
||||||
Thank you!
|
Thank you!
|
||||||
|
|
||||||
|
|||||||
41
index.js
41
index.js
@@ -41,7 +41,7 @@ var Sharp = function(input) {
|
|||||||
heightPost: -1,
|
heightPost: -1,
|
||||||
width: -1,
|
width: -1,
|
||||||
height: -1,
|
height: -1,
|
||||||
canvas: 'c',
|
canvas: 'crop',
|
||||||
gravity: 0,
|
gravity: 0,
|
||||||
angle: 0,
|
angle: 0,
|
||||||
rotateBeforePreExtract: false,
|
rotateBeforePreExtract: false,
|
||||||
@@ -83,11 +83,13 @@ var Sharp = function(input) {
|
|||||||
(input[0] === 0x52 && input[1] === 0x49) ||
|
(input[0] === 0x52 && input[1] === 0x49) ||
|
||||||
// TIFF
|
// TIFF
|
||||||
(input[0] === 0x4D && input[1] === 0x4D && input[2] === 0x00 && (input[3] === 0x2A || input[3] === 0x2B)) ||
|
(input[0] === 0x4D && input[1] === 0x4D && input[2] === 0x00 && (input[3] === 0x2A || input[3] === 0x2B)) ||
|
||||||
(input[0] === 0x49 && input[1] === 0x49 && (input[2] === 0x2A || input[2] === 0x2B) && input[3] === 0x00)
|
(input[0] === 0x49 && input[1] === 0x49 && (input[2] === 0x2A || input[2] === 0x2B) && input[3] === 0x00) ||
|
||||||
|
// GIF
|
||||||
|
(input[0] === 0x47 && input[1] === 0x49 && input[2] === 0x46 && input[3] === 0x38 && (input[4] === 0x37 || input[4] === 0x39) && input[5] === 0x61)
|
||||||
) {
|
) {
|
||||||
this.options.bufferIn = input;
|
this.options.bufferIn = input;
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Buffer contains an unsupported image format. JPEG, PNG, WebP and TIFF are currently supported.');
|
throw new Error('Buffer contains an unsupported image format. JPEG, PNG, WebP, TIFF and GIF are currently supported.');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// input=stream
|
// input=stream
|
||||||
@@ -98,6 +100,11 @@ var Sharp = function(input) {
|
|||||||
module.exports = Sharp;
|
module.exports = Sharp;
|
||||||
util.inherits(Sharp, stream.Duplex);
|
util.inherits(Sharp, stream.Duplex);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Supported image formats
|
||||||
|
*/
|
||||||
|
module.exports.format = sharp.format();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Handle incoming chunk on Writable Stream
|
Handle incoming chunk on Writable Stream
|
||||||
*/
|
*/
|
||||||
@@ -129,7 +136,7 @@ Sharp.prototype._write = function(chunk, encoding, callback) {
|
|||||||
module.exports.gravity = {'center': 0, 'centre': 0, 'north': 1, 'east': 2, 'south': 3, 'west': 4};
|
module.exports.gravity = {'center': 0, 'centre': 0, 'north': 1, 'east': 2, 'south': 3, 'west': 4};
|
||||||
|
|
||||||
Sharp.prototype.crop = function(gravity) {
|
Sharp.prototype.crop = function(gravity) {
|
||||||
this.options.canvas = 'c';
|
this.options.canvas = 'crop';
|
||||||
if (typeof gravity === 'number' && !Number.isNaN(gravity) && gravity >= 0 && gravity <= 4) {
|
if (typeof gravity === 'number' && !Number.isNaN(gravity) && gravity >= 0 && gravity <= 4) {
|
||||||
this.options.gravity = gravity;
|
this.options.gravity = gravity;
|
||||||
} else {
|
} else {
|
||||||
@@ -169,12 +176,17 @@ Sharp.prototype.background = function(rgba) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Sharp.prototype.embed = function() {
|
Sharp.prototype.embed = function() {
|
||||||
this.options.canvas = 'e';
|
this.options.canvas = 'embed';
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
Sharp.prototype.max = function() {
|
Sharp.prototype.max = function() {
|
||||||
this.options.canvas = 'm';
|
this.options.canvas = 'max';
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Sharp.prototype.min = function() {
|
||||||
|
this.options.canvas = 'min';
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -479,7 +491,8 @@ Sharp.prototype.webp = function() {
|
|||||||
Force raw, uint8 output
|
Force raw, uint8 output
|
||||||
*/
|
*/
|
||||||
Sharp.prototype.raw = function() {
|
Sharp.prototype.raw = function() {
|
||||||
if (semver.gte(libvipsVersion, '7.42.0')) {
|
var supportsRawOutput = module.exports.format.raw.output;
|
||||||
|
if (supportsRawOutput.file || supportsRawOutput.buffer || supportsRawOutput.stream) {
|
||||||
this.options.output = '__raw';
|
this.options.output = '__raw';
|
||||||
} else {
|
} else {
|
||||||
console.error('Raw output requires libvips 7.42.0+');
|
console.error('Raw output requires libvips 7.42.0+');
|
||||||
@@ -489,15 +502,15 @@ Sharp.prototype.raw = function() {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Force output to a given format
|
Force output to a given format
|
||||||
|
@param format is either the id as a String or an Object with an 'id' attribute
|
||||||
*/
|
*/
|
||||||
module.exports.format = {'jpeg': 'jpeg', 'png': 'png', 'webp': 'webp', 'raw': 'raw'};
|
|
||||||
Sharp.prototype.toFormat = function(format) {
|
Sharp.prototype.toFormat = function(format) {
|
||||||
if (
|
var id = format;
|
||||||
typeof format === 'string' &&
|
if (typeof format === 'object') {
|
||||||
typeof module.exports.format[format] === 'string' &&
|
id = format.id;
|
||||||
typeof this[format] === 'function'
|
}
|
||||||
) {
|
if (typeof id === 'string' && typeof module.exports.format[id] === 'object' && typeof this[id] === 'function') {
|
||||||
this[format]();
|
this[id]();
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unsupported format ' + format);
|
throw new Error('Unsupported format ' + format);
|
||||||
}
|
}
|
||||||
|
|||||||
12
package.json
12
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sharp",
|
"name": "sharp",
|
||||||
"version": "0.9.2",
|
"version": "0.9.3",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
"Pierre Inglebert <pierre.inglebert@gmail.com>",
|
"Pierre Inglebert <pierre.inglebert@gmail.com>",
|
||||||
@@ -11,7 +11,9 @@
|
|||||||
"Julian Walker <julian@fiftythree.com>",
|
"Julian Walker <julian@fiftythree.com>",
|
||||||
"Amit Pitaru <pitaru.amit@gmail.com>",
|
"Amit Pitaru <pitaru.amit@gmail.com>",
|
||||||
"Brandon Aaron <hello.brandon@aaron.sh>",
|
"Brandon Aaron <hello.brandon@aaron.sh>",
|
||||||
"Andreas Lind <andreas@one.com>"
|
"Andreas Lind <andreas@one.com>",
|
||||||
|
"Maurus Cuelenaere <mcuelenaere@gmail.com>",
|
||||||
|
"Linus Unnebäck <linus@folkdatorn.se>"
|
||||||
],
|
],
|
||||||
"description": "High performance Node.js module to resize JPEG, PNG, WebP and TIFF images using the libvips library",
|
"description": "High performance Node.js module to resize JPEG, PNG, WebP and TIFF images using the libvips library",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -34,15 +36,15 @@
|
|||||||
"vips"
|
"vips"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bluebird": "^2.9.9",
|
"bluebird": "^2.9.12",
|
||||||
"color": "^0.7.3",
|
"color": "^0.7.3",
|
||||||
"nan": "^1.6.2",
|
"nan": "^1.6.2",
|
||||||
"semver": "^4.3.0"
|
"semver": "^4.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"mocha": "^2.1.0",
|
"mocha": "^2.1.0",
|
||||||
"mocha-jshint": "^0.0.9",
|
"mocha-jshint": "^0.0.9",
|
||||||
"istanbul": "^0.3.5",
|
"istanbul": "^0.3.6",
|
||||||
"coveralls": "^2.11.2",
|
"coveralls": "^2.11.2",
|
||||||
"node-cpplint": "^0.4.0"
|
"node-cpplint": "^0.4.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,22 +13,22 @@
|
|||||||
# * Amazon Linux 2014.09
|
# * Amazon Linux 2014.09
|
||||||
|
|
||||||
vips_version_minimum=7.40.0
|
vips_version_minimum=7.40.0
|
||||||
vips_version_latest_major=7.42
|
vips_version_latest_major_minor=7.42
|
||||||
vips_version_latest_minor=2
|
vips_version_latest_patch=3
|
||||||
|
|
||||||
install_libvips_from_source() {
|
install_libvips_from_source() {
|
||||||
echo "Compiling libvips $vips_version_latest_major.$vips_version_latest_minor from source"
|
echo "Compiling libvips $vips_version_latest_major_minor.$vips_version_latest_patch from source"
|
||||||
curl -O http://www.vips.ecs.soton.ac.uk/supported/$vips_version_latest_major/vips-$vips_version_latest_major.$vips_version_latest_minor.tar.gz
|
curl -O http://www.vips.ecs.soton.ac.uk/supported/$vips_version_latest_major_minor/vips-$vips_version_latest_major_minor.$vips_version_latest_patch.tar.gz
|
||||||
tar zvxf vips-$vips_version_latest_major.$vips_version_latest_minor.tar.gz
|
tar zvxf vips-$vips_version_latest_major_minor.$vips_version_latest_patch.tar.gz
|
||||||
cd vips-$vips_version_latest_major.$vips_version_latest_minor
|
cd vips-$vips_version_latest_major_minor.$vips_version_latest_patch
|
||||||
./configure --enable-debug=no --enable-docs=no --enable-cxx=yes --without-python --without-orc --without-fftw --without-gsf $1
|
./configure --enable-debug=no --enable-docs=no --enable-cxx=yes --without-python --without-orc --without-fftw $1
|
||||||
make
|
make
|
||||||
make install
|
make install
|
||||||
cd ..
|
cd ..
|
||||||
rm -rf vips-$vips_version_latest_major.$vips_version_latest_minor
|
rm -rf vips-$vips_version_latest_major_minor.$vips_version_latest_patch
|
||||||
rm vips-$vips_version_latest_major.$vips_version_latest_minor.tar.gz
|
rm vips-$vips_version_latest_major_minor.$vips_version_latest_patch.tar.gz
|
||||||
ldconfig
|
ldconfig
|
||||||
echo "Installed libvips $vips_version_latest_major.$vips_version_latest_minor"
|
echo "Installed libvips $vips_version_latest_major_minor.$vips_version_latest_patch"
|
||||||
}
|
}
|
||||||
|
|
||||||
sorry() {
|
sorry() {
|
||||||
@@ -90,12 +90,12 @@ case $(uname -s) in
|
|||||||
jessie|vivid)
|
jessie|vivid)
|
||||||
# Debian 8, Ubuntu 15
|
# Debian 8, Ubuntu 15
|
||||||
echo "Installing libvips via apt-get"
|
echo "Installing libvips via apt-get"
|
||||||
apt-get install -y libvips-dev
|
apt-get install -y libvips-dev libgsf-1-dev
|
||||||
;;
|
;;
|
||||||
trusty|utopic|qiana|rebecca)
|
trusty|utopic|qiana|rebecca)
|
||||||
# Ubuntu 14, Mint 17
|
# Ubuntu 14, Mint 17
|
||||||
echo "Installing libvips dependencies via apt-get"
|
echo "Installing libvips dependencies via apt-get"
|
||||||
apt-get install -y automake build-essential gobject-introspection gtk-doc-tools libglib2.0-dev libjpeg-turbo8-dev libpng12-dev libwebp-dev libtiff5-dev libexif-dev liblcms2-dev libxml2-dev swig libmagickcore-dev curl
|
apt-get install -y automake build-essential gobject-introspection gtk-doc-tools libglib2.0-dev libjpeg-turbo8-dev libpng12-dev libwebp-dev libtiff5-dev libexif-dev libgsf-1-dev liblcms2-dev libxml2-dev swig libmagickcore-dev curl
|
||||||
install_libvips_from_source
|
install_libvips_from_source
|
||||||
;;
|
;;
|
||||||
precise|wheezy|maya)
|
precise|wheezy|maya)
|
||||||
@@ -103,7 +103,7 @@ case $(uname -s) in
|
|||||||
echo "Installing libvips dependencies via apt-get"
|
echo "Installing libvips dependencies via apt-get"
|
||||||
add-apt-repository -y ppa:lyrasis/precise-backports
|
add-apt-repository -y ppa:lyrasis/precise-backports
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y automake build-essential gobject-introspection gtk-doc-tools libglib2.0-dev libjpeg-turbo8-dev libpng12-dev libwebp-dev libtiff4-dev libexif-dev liblcms2-dev libxml2-dev swig libmagickcore-dev curl
|
apt-get install -y automake build-essential gobject-introspection gtk-doc-tools libglib2.0-dev libjpeg-turbo8-dev libpng12-dev libwebp-dev libtiff4-dev libexif-dev libgsf-1-dev liblcms2-dev libxml2-dev swig libmagickcore-dev curl
|
||||||
install_libvips_from_source
|
install_libvips_from_source
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -120,14 +120,14 @@ case $(uname -s) in
|
|||||||
# RHEL/CentOS 7
|
# RHEL/CentOS 7
|
||||||
echo "Installing libvips dependencies via yum"
|
echo "Installing libvips dependencies via yum"
|
||||||
yum groupinstall -y "Development Tools"
|
yum groupinstall -y "Development Tools"
|
||||||
yum install -y gtk-doc libxml2-devel libjpeg-turbo-devel libpng-devel libtiff-devel libexif-devel lcms-devel ImageMagick-devel gobject-introspection-devel libwebp-devel curl
|
yum install -y gtk-doc libxml2-devel libjpeg-turbo-devel libpng-devel libtiff-devel libexif-devel libgsf-devel lcms-devel ImageMagick-devel gobject-introspection-devel libwebp-devel curl
|
||||||
install_libvips_from_source "--prefix=/usr"
|
install_libvips_from_source "--prefix=/usr"
|
||||||
;;
|
;;
|
||||||
"Red Hat Enterprise Linux release 6."*|"CentOS release 6."*|"Scientific Linux release 6."*)
|
"Red Hat Enterprise Linux release 6."*|"CentOS release 6."*|"Scientific Linux release 6."*)
|
||||||
# RHEL/CentOS 6
|
# RHEL/CentOS 6
|
||||||
echo "Installing libvips dependencies via yum"
|
echo "Installing libvips dependencies via yum"
|
||||||
yum groupinstall -y "Development Tools"
|
yum groupinstall -y "Development Tools"
|
||||||
yum install -y gtk-doc libxml2-devel libjpeg-turbo-devel libpng-devel libtiff-devel libexif-devel lcms-devel ImageMagick-devel curl
|
yum install -y gtk-doc libxml2-devel libjpeg-turbo-devel libpng-devel libtiff-devel libexif-devel libgsf-devel lcms-devel ImageMagick-devel curl
|
||||||
yum install -y http://li.nux.ro/download/nux/dextop/el6/x86_64/nux-dextop-release-0-2.el6.nux.noarch.rpm
|
yum install -y http://li.nux.ro/download/nux/dextop/el6/x86_64/nux-dextop-release-0-2.el6.nux.noarch.rpm
|
||||||
yum install -y --enablerepo=nux-dextop gobject-introspection-devel
|
yum install -y --enablerepo=nux-dextop gobject-introspection-devel
|
||||||
yum install -y http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
|
yum install -y http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
|
||||||
@@ -153,7 +153,7 @@ case $(uname -s) in
|
|||||||
echo "Detected '$RELEASE'"
|
echo "Detected '$RELEASE'"
|
||||||
echo "Installing libvips dependencies via yum"
|
echo "Installing libvips dependencies via yum"
|
||||||
yum groupinstall -y "Development Tools"
|
yum groupinstall -y "Development Tools"
|
||||||
yum install -y gtk-doc libxml2-devel libjpeg-turbo-devel libpng-devel libtiff-devel libexif-devel lcms-devel ImageMagick-devel gobject-introspection-devel libwebp-devel curl
|
yum install -y gtk-doc libxml2-devel libjpeg-turbo-devel libpng-devel libtiff-devel libexif-devel libgsf-devel lcms-devel ImageMagick-devel gobject-introspection-devel libwebp-devel curl
|
||||||
install_libvips_from_source "--prefix=/usr"
|
install_libvips_from_source "--prefix=/usr"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
@@ -43,6 +43,15 @@ namespace sharp {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool buffer_is_gif(char *buffer, size_t len) {
|
||||||
|
return (
|
||||||
|
len >= 6 && (
|
||||||
|
(buffer[0] == 'G' && buffer[1] == 'I' && buffer[2] == 'F' &&
|
||||||
|
buffer[3] == '8' && (buffer[4] == '7' || buffer[4] == '9') && buffer[5] == 'a')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Determine image format of a buffer.
|
Determine image format of a buffer.
|
||||||
*/
|
*/
|
||||||
@@ -57,6 +66,8 @@ namespace sharp {
|
|||||||
imageType = ImageType::WEBP;
|
imageType = ImageType::WEBP;
|
||||||
} else if (buffer_is_tiff(static_cast<char*>(buffer), length)) {
|
} else if (buffer_is_tiff(static_cast<char*>(buffer), length)) {
|
||||||
imageType = ImageType::TIFF;
|
imageType = ImageType::TIFF;
|
||||||
|
} else if (buffer_is_gif(static_cast<char*>(buffer), length)) {
|
||||||
|
imageType = ImageType::MAGICK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return imageType;
|
return imageType;
|
||||||
@@ -75,6 +86,10 @@ namespace sharp {
|
|||||||
vips_webpload_buffer(buffer, length, &image, "access", access, NULL);
|
vips_webpload_buffer(buffer, length, &image, "access", access, NULL);
|
||||||
} else if (imageType == ImageType::TIFF) {
|
} else if (imageType == ImageType::TIFF) {
|
||||||
vips_tiffload_buffer(buffer, length, &image, "access", access, NULL);
|
vips_tiffload_buffer(buffer, length, &image, "access", access, NULL);
|
||||||
|
#if (VIPS_MAJOR_VERSION >= 8)
|
||||||
|
} else if (imageType == ImageType::MAGICK) {
|
||||||
|
vips_magickload_buffer(buffer, length, &image, "access", access, NULL);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,9 @@ using sharp::counterQueue;
|
|||||||
|
|
||||||
enum class Canvas {
|
enum class Canvas {
|
||||||
CROP,
|
CROP,
|
||||||
|
EMBED,
|
||||||
MAX,
|
MAX,
|
||||||
EMBED
|
MIN
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Angle {
|
enum class Angle {
|
||||||
@@ -247,19 +248,34 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
int interpolatorWindowSize = InterpolatorWindowSize(baton->interpolator.c_str());
|
int interpolatorWindowSize = InterpolatorWindowSize(baton->interpolator.c_str());
|
||||||
|
|
||||||
// Scaling calculations
|
// Scaling calculations
|
||||||
double factor;
|
double factor = 1.0;
|
||||||
if (baton->width > 0 && baton->height > 0) {
|
if (baton->width > 0 && baton->height > 0) {
|
||||||
// Fixed width and height
|
// Fixed width and height
|
||||||
double xfactor = static_cast<double>(inputWidth) / static_cast<double>(baton->width);
|
double xfactor = static_cast<double>(inputWidth) / static_cast<double>(baton->width);
|
||||||
double yfactor = static_cast<double>(inputHeight) / static_cast<double>(baton->height);
|
double yfactor = static_cast<double>(inputHeight) / static_cast<double>(baton->height);
|
||||||
factor = (baton->canvas == Canvas::CROP) ? std::min(xfactor, yfactor) : std::max(xfactor, yfactor);
|
switch (baton->canvas) {
|
||||||
// if max is set, we need to compute the real size of the thumb image
|
case Canvas::CROP:
|
||||||
if (baton->canvas == Canvas::MAX) {
|
factor = std::min(xfactor, yfactor);
|
||||||
if (xfactor > yfactor) {
|
break;
|
||||||
baton->height = round(static_cast<double>(inputHeight) / xfactor);
|
case Canvas::EMBED:
|
||||||
} else {
|
factor = std::max(xfactor, yfactor);
|
||||||
baton->width = round(static_cast<double>(inputWidth) / yfactor);
|
break;
|
||||||
}
|
case Canvas::MAX:
|
||||||
|
factor = std::max(xfactor, yfactor);
|
||||||
|
if (xfactor > yfactor) {
|
||||||
|
baton->height = round(static_cast<double>(inputHeight) / xfactor);
|
||||||
|
} else {
|
||||||
|
baton->width = round(static_cast<double>(inputWidth) / yfactor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Canvas::MIN:
|
||||||
|
factor = std::min(xfactor, yfactor);
|
||||||
|
if (xfactor < yfactor) {
|
||||||
|
baton->height = round(static_cast<double>(inputHeight) / xfactor);
|
||||||
|
} else {
|
||||||
|
baton->width = round(static_cast<double>(inputWidth) / yfactor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else if (baton->width > 0) {
|
} else if (baton->width > 0) {
|
||||||
// Fixed width, auto height
|
// Fixed width, auto height
|
||||||
@@ -271,7 +287,6 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
baton->width = floor(static_cast<double>(inputWidth) / factor);
|
baton->width = floor(static_cast<double>(inputWidth) / factor);
|
||||||
} else {
|
} else {
|
||||||
// Identity transform
|
// Identity transform
|
||||||
factor = 1;
|
|
||||||
baton->width = inputWidth;
|
baton->width = inputWidth;
|
||||||
baton->height = inputHeight;
|
baton->height = inputHeight;
|
||||||
}
|
}
|
||||||
@@ -549,7 +564,7 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
vips_object_local(hook, embedded);
|
vips_object_local(hook, embedded);
|
||||||
image = embedded;
|
image = embedded;
|
||||||
} else {
|
} else {
|
||||||
// Crop/max
|
// Crop/max/min
|
||||||
int left;
|
int left;
|
||||||
int top;
|
int top;
|
||||||
std::tie(left, top) = CalculateCrop(image->Xsize, image->Ysize, baton->width, baton->height, baton->gravity);
|
std::tie(left, top) = CalculateCrop(image->Xsize, image->Ysize, baton->width, baton->height, baton->gravity);
|
||||||
@@ -661,7 +676,7 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !(VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 40 && VIPS_MINOR_VERSION >= 5)
|
#if !(VIPS_MAJOR_VERSION >= 8 || (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 40 && VIPS_MINOR_VERSION >= 5))
|
||||||
// Generate image tile cache when interlace output is required - no longer required as of libvips 7.40.5+
|
// Generate image tile cache when interlace output is required - no longer required as of libvips 7.40.5+
|
||||||
if (baton->progressive) {
|
if (baton->progressive) {
|
||||||
VipsImage *cached;
|
VipsImage *cached;
|
||||||
@@ -683,7 +698,7 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
}
|
}
|
||||||
baton->outputFormat = "jpeg";
|
baton->outputFormat = "jpeg";
|
||||||
} else if (baton->output == "__png" || (baton->output == "__input" && inputImageType == ImageType::PNG)) {
|
} else if (baton->output == "__png" || (baton->output == "__input" && inputImageType == ImageType::PNG)) {
|
||||||
#if (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 42)
|
#if (VIPS_MAJOR_VERSION >= 8 || (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 42))
|
||||||
// Select PNG row filter
|
// Select PNG row filter
|
||||||
int filter = baton->withoutAdaptiveFiltering ? VIPS_FOREIGN_PNG_FILTER_NONE : VIPS_FOREIGN_PNG_FILTER_ALL;
|
int filter = baton->withoutAdaptiveFiltering ? VIPS_FOREIGN_PNG_FILTER_NONE : VIPS_FOREIGN_PNG_FILTER_ALL;
|
||||||
// Write PNG to buffer
|
// Write PNG to buffer
|
||||||
@@ -706,7 +721,7 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
baton->outputFormat = "webp";
|
baton->outputFormat = "webp";
|
||||||
#if (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 42)
|
#if (VIPS_MAJOR_VERSION >= 8 || (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 42))
|
||||||
} else if (baton->output == "__raw") {
|
} else if (baton->output == "__raw") {
|
||||||
// Write raw, uncompressed image data to buffer
|
// Write raw, uncompressed image data to buffer
|
||||||
if (baton->greyscale) {
|
if (baton->greyscale) {
|
||||||
@@ -750,7 +765,7 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
}
|
}
|
||||||
baton->outputFormat = "jpeg";
|
baton->outputFormat = "jpeg";
|
||||||
} else if (outputPng || (matchInput && inputImageType == ImageType::PNG)) {
|
} else if (outputPng || (matchInput && inputImageType == ImageType::PNG)) {
|
||||||
#if (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 42)
|
#if (VIPS_MAJOR_VERSION >= 8 || (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 42))
|
||||||
// Select PNG row filter
|
// Select PNG row filter
|
||||||
int filter = baton->withoutAdaptiveFiltering ? VIPS_FOREIGN_PNG_FILTER_NONE : VIPS_FOREIGN_PNG_FILTER_ALL;
|
int filter = baton->withoutAdaptiveFiltering ? VIPS_FOREIGN_PNG_FILTER_NONE : VIPS_FOREIGN_PNG_FILTER_ALL;
|
||||||
// Write PNG to file
|
// Write PNG to file
|
||||||
@@ -963,12 +978,14 @@ NAN_METHOD(resize) {
|
|||||||
baton->height = options->Get(NanNew<String>("height"))->Int32Value();
|
baton->height = options->Get(NanNew<String>("height"))->Int32Value();
|
||||||
// Canvas option
|
// Canvas option
|
||||||
Local<String> canvas = options->Get(NanNew<String>("canvas"))->ToString();
|
Local<String> canvas = options->Get(NanNew<String>("canvas"))->ToString();
|
||||||
if (canvas->Equals(NanNew<String>("c"))) {
|
if (canvas->Equals(NanNew<String>("crop"))) {
|
||||||
baton->canvas = Canvas::CROP;
|
baton->canvas = Canvas::CROP;
|
||||||
} else if (canvas->Equals(NanNew<String>("m"))) {
|
} else if (canvas->Equals(NanNew<String>("embed"))) {
|
||||||
baton->canvas = Canvas::MAX;
|
|
||||||
} else if (canvas->Equals(NanNew<String>("e"))) {
|
|
||||||
baton->canvas = Canvas::EMBED;
|
baton->canvas = Canvas::EMBED;
|
||||||
|
} else if (canvas->Equals(NanNew<String>("max"))) {
|
||||||
|
baton->canvas = Canvas::MAX;
|
||||||
|
} else if (canvas->Equals(NanNew<String>("min"))) {
|
||||||
|
baton->canvas = Canvas::MIN;
|
||||||
}
|
}
|
||||||
// Background colour
|
// Background colour
|
||||||
Local<Array> background = Local<Array>::Cast(options->Get(NanNew<String>("background")));
|
Local<Array> background = Local<Array>::Cast(options->Get(NanNew<String>("background")));
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ extern "C" void init(v8::Handle<v8::Object> target) {
|
|||||||
NODE_SET_METHOD(target, "concurrency", concurrency);
|
NODE_SET_METHOD(target, "concurrency", concurrency);
|
||||||
NODE_SET_METHOD(target, "counters", counters);
|
NODE_SET_METHOD(target, "counters", counters);
|
||||||
NODE_SET_METHOD(target, "libvipsVersion", libvipsVersion);
|
NODE_SET_METHOD(target, "libvipsVersion", libvipsVersion);
|
||||||
|
NODE_SET_METHOD(target, "format", format);
|
||||||
}
|
}
|
||||||
|
|
||||||
NODE_MODULE(sharp, init)
|
NODE_MODULE(sharp, init)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using v8::Local;
|
|||||||
using v8::Object;
|
using v8::Object;
|
||||||
using v8::Number;
|
using v8::Number;
|
||||||
using v8::String;
|
using v8::String;
|
||||||
|
using v8::Boolean;
|
||||||
|
|
||||||
using sharp::counterQueue;
|
using sharp::counterQueue;
|
||||||
using sharp::counterProcess;
|
using sharp::counterProcess;
|
||||||
@@ -78,3 +79,66 @@ NAN_METHOD(libvipsVersion) {
|
|||||||
snprintf(version, sizeof(version), "%d.%d.%d", vips_version(0), vips_version(1), vips_version(2));
|
snprintf(version, sizeof(version), "%d.%d.%d", vips_version(0), vips_version(1), vips_version(2));
|
||||||
NanReturnValue(NanNew<String>(version));
|
NanReturnValue(NanNew<String>(version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get available input/output file/buffer/stream formats
|
||||||
|
*/
|
||||||
|
NAN_METHOD(format) {
|
||||||
|
NanScope();
|
||||||
|
|
||||||
|
// Attribute names
|
||||||
|
Local<String> attrId = NanNew<String>("id");
|
||||||
|
Local<String> attrInput = NanNew<String>("input");
|
||||||
|
Local<String> attrOutput = NanNew<String>("output");
|
||||||
|
Local<String> attrFile = NanNew<String>("file");
|
||||||
|
Local<String> attrBuffer = NanNew<String>("buffer");
|
||||||
|
Local<String> attrStream = NanNew<String>("stream");
|
||||||
|
|
||||||
|
// Which load/save operations are available for each compressed format?
|
||||||
|
Local<Object> format = NanNew<Object>();
|
||||||
|
for (std::string f : {"jpeg", "png", "webp", "tiff", "magick", "openslide", "dz"}) {
|
||||||
|
// Input
|
||||||
|
Local<Object> input = NanNew<Object>();
|
||||||
|
input->Set(attrFile, NanNew<Boolean>(
|
||||||
|
vips_type_find("VipsOperation", (f + "load").c_str())));
|
||||||
|
input->Set(attrBuffer, NanNew<Boolean>(
|
||||||
|
vips_type_find("VipsOperation", (f + "load_buffer").c_str())));
|
||||||
|
input->Set(attrStream, input->Get(attrBuffer));
|
||||||
|
// Output
|
||||||
|
Local<Object> output = NanNew<Object>();
|
||||||
|
output->Set(attrFile, NanNew<Boolean>(
|
||||||
|
vips_type_find("VipsOperation", (f + "save").c_str())));
|
||||||
|
output->Set(attrBuffer, NanNew<Boolean>(
|
||||||
|
vips_type_find("VipsOperation", (f + "save_buffer").c_str())));
|
||||||
|
output->Set(attrStream, output->Get(attrBuffer));
|
||||||
|
// Other attributes
|
||||||
|
Local<Object> container = NanNew<Object>();
|
||||||
|
Local<String> formatId = NanNew<String>(f);
|
||||||
|
container->Set(attrId, formatId);
|
||||||
|
container->Set(attrInput, input);
|
||||||
|
container->Set(attrOutput, output);
|
||||||
|
// Add to set of formats
|
||||||
|
format->Set(formatId, container);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw, uncompressed data
|
||||||
|
Local<Object> raw = NanNew<Object>();
|
||||||
|
raw->Set(attrId, NanNew<String>("raw"));
|
||||||
|
format->Set(NanNew<String>("raw"), raw);
|
||||||
|
// No support for raw input yet, so always false
|
||||||
|
Local<Boolean> unsupported = NanNew<Boolean>(false);
|
||||||
|
Local<Object> rawInput = NanNew<Object>();
|
||||||
|
rawInput->Set(attrFile, unsupported);
|
||||||
|
rawInput->Set(attrBuffer, unsupported);
|
||||||
|
rawInput->Set(attrStream, unsupported);
|
||||||
|
raw->Set(attrInput, rawInput);
|
||||||
|
// Raw output via Buffer/Stream is available in libvips >= 7.42.0
|
||||||
|
Local<Boolean> supportsRawOutput = NanNew<Boolean>(vips_version(0) >= 8 || (vips_version(0) == 7 && vips_version(1) >= 42));
|
||||||
|
Local<Object> rawOutput = NanNew<Object>();
|
||||||
|
rawOutput->Set(attrFile, unsupported);
|
||||||
|
rawOutput->Set(attrBuffer, supportsRawOutput);
|
||||||
|
rawOutput->Set(attrStream, supportsRawOutput);
|
||||||
|
raw->Set(attrOutput, rawOutput);
|
||||||
|
|
||||||
|
NanReturnValue(format);
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,5 +7,6 @@ NAN_METHOD(cache);
|
|||||||
NAN_METHOD(concurrency);
|
NAN_METHOD(concurrency);
|
||||||
NAN_METHOD(counters);
|
NAN_METHOD(counters);
|
||||||
NAN_METHOD(libvipsVersion);
|
NAN_METHOD(libvipsVersion);
|
||||||
|
NAN_METHOD(format);
|
||||||
|
|
||||||
#endif // SRC_UTILITIES_H_
|
#endif // SRC_UTILITIES_H_
|
||||||
|
|||||||
@@ -488,39 +488,43 @@ describe('Input/output', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Convert SVG, if supported, to PNG', function(done) {
|
if (sharp.format.magick.input.file) {
|
||||||
sharp(fixtures.inputSvg)
|
it('Convert SVG, if supported, to PNG', function(done) {
|
||||||
.resize(100, 100)
|
sharp(fixtures.inputSvg)
|
||||||
.toFormat('png')
|
.resize(100, 100)
|
||||||
.toFile(fixtures.path('output.svg.png'), function(err, info) {
|
.toFormat('png')
|
||||||
if (err) {
|
.toFile(fixtures.path('output.svg.png'), function(err, info) {
|
||||||
assert.strictEqual('Input file is of an unsupported image format', err.message);
|
if (err) {
|
||||||
} else {
|
assert.strictEqual('Input file is of an unsupported image format', err.message);
|
||||||
|
} else {
|
||||||
|
assert.strictEqual(true, info.size > 0);
|
||||||
|
assert.strictEqual('png', info.format);
|
||||||
|
assert.strictEqual(100, info.width);
|
||||||
|
assert.strictEqual(100, info.height);
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sharp.format.magick.input.file) {
|
||||||
|
it('Convert PSD to PNG', function(done) {
|
||||||
|
sharp(fixtures.inputPsd)
|
||||||
|
.resize(320, 240)
|
||||||
|
.toFormat(sharp.format.png)
|
||||||
|
.toFile(fixtures.path('output.psd.png'), function(err, info) {
|
||||||
|
if (err) throw err;
|
||||||
assert.strictEqual(true, info.size > 0);
|
assert.strictEqual(true, info.size > 0);
|
||||||
assert.strictEqual('png', info.format);
|
assert.strictEqual('png', info.format);
|
||||||
assert.strictEqual(100, info.width);
|
assert.strictEqual(320, info.width);
|
||||||
assert.strictEqual(100, info.height);
|
assert.strictEqual(240, info.height);
|
||||||
}
|
done();
|
||||||
done();
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
it('Convert PSD to PNG', function(done) {
|
if (sharp.format.tiff.input.buffer) {
|
||||||
sharp(fixtures.inputPsd)
|
it('Load TIFF from Buffer', function(done) {
|
||||||
.resize(320, 240)
|
|
||||||
.toFormat(sharp.format.png)
|
|
||||||
.toFile(fixtures.path('output.psd.png'), function(err, info) {
|
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual(true, info.size > 0);
|
|
||||||
assert.strictEqual('png', info.format);
|
|
||||||
assert.strictEqual(320, info.width);
|
|
||||||
assert.strictEqual(240, info.height);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (semver.gte(sharp.libvipsVersion(), '7.40.0')) {
|
|
||||||
it('Load TIFF from Buffer [libvips ' + sharp.libvipsVersion() + '>=7.40.0]', function(done) {
|
|
||||||
var inputTiffBuffer = fs.readFileSync(fixtures.inputTiff);
|
var inputTiffBuffer = fs.readFileSync(fixtures.inputTiff);
|
||||||
sharp(inputTiffBuffer)
|
sharp(inputTiffBuffer)
|
||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
@@ -537,8 +541,26 @@ describe('Input/output', function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (semver.gte(sharp.libvipsVersion(), '7.42.0')) {
|
if (sharp.format.magick.input.buffer) {
|
||||||
describe('Ouput raw, uncompressed image data [libvips ' + sharp.libvipsVersion() + '>=7.42.0]', function() {
|
it('Load GIF from Buffer', function(done) {
|
||||||
|
var inputGifBuffer = fs.readFileSync(fixtures.inputGif);
|
||||||
|
sharp(inputGifBuffer)
|
||||||
|
.resize(320, 240)
|
||||||
|
.jpeg()
|
||||||
|
.toBuffer(function(err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, data.length > 0);
|
||||||
|
assert.strictEqual(data.length, info.size);
|
||||||
|
assert.strictEqual('jpeg', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(240, info.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sharp.format.raw.output.buffer) {
|
||||||
|
describe('Ouput raw, uncompressed image data', function() {
|
||||||
it('1 channel greyscale image', function(done) {
|
it('1 channel greyscale image', function(done) {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.greyscale()
|
.greyscale()
|
||||||
|
|||||||
@@ -185,6 +185,39 @@ describe('Resize dimensions', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Min width or height considering ratio (landscape)', function(done) {
|
||||||
|
sharp(fixtures.inputJpg).resize(320, 320).min().toBuffer(function(err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, data.length > 0);
|
||||||
|
assert.strictEqual('jpeg', info.format);
|
||||||
|
assert.strictEqual(392, info.width);
|
||||||
|
assert.strictEqual(320, info.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Min width or height considering ratio (portrait)', function(done) {
|
||||||
|
sharp(fixtures.inputTiff).resize(320, 320).min().jpeg().toBuffer(function(err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, data.length > 0);
|
||||||
|
assert.strictEqual('jpeg', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(422, info.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Provide only one dimension with min, should default to crop', function(done) {
|
||||||
|
sharp(fixtures.inputJpg).resize(320).min().toBuffer(function(err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, data.length > 0);
|
||||||
|
assert.strictEqual('jpeg', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(261, info.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('Do not enlarge when input width is already less than output width', function(done) {
|
it('Do not enlarge when input width is already less than output width', function(done) {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.resize(2800)
|
.resize(2800)
|
||||||
|
|||||||
@@ -50,4 +50,25 @@ describe('Utilities', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Format', function() {
|
||||||
|
it('Contains expected attributes', function() {
|
||||||
|
assert.strictEqual('object', typeof sharp.format);
|
||||||
|
Object.keys(sharp.format).forEach(function(format) {
|
||||||
|
assert.strictEqual(true, 'id' in sharp.format[format]);
|
||||||
|
assert.strictEqual(format, sharp.format[format].id);
|
||||||
|
['input', 'output'].forEach(function(direction) {
|
||||||
|
assert.strictEqual(true, direction in sharp.format[format]);
|
||||||
|
assert.strictEqual('object', typeof sharp.format[format][direction]);
|
||||||
|
assert.strictEqual(3, Object.keys(sharp.format[format][direction]).length);
|
||||||
|
assert.strictEqual(true, 'file' in sharp.format[format][direction]);
|
||||||
|
assert.strictEqual(true, 'buffer' in sharp.format[format][direction]);
|
||||||
|
assert.strictEqual(true, 'stream' in sharp.format[format][direction]);
|
||||||
|
assert.strictEqual('boolean', typeof sharp.format[format][direction].file);
|
||||||
|
assert.strictEqual('boolean', typeof sharp.format[format][direction].buffer);
|
||||||
|
assert.strictEqual('boolean', typeof sharp.format[format][direction].stream);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user