Compare commits

...

17 Commits

Author SHA1 Message Date
Lovell Fuller
d6051dd714 Release v0.18.2 2017-07-01 09:52:47 +01:00
Lovell Fuller
53ff061efa Document SHARP_DIST_BASE_URL #841 2017-07-01 09:44:02 +01:00
Lovell Fuller
72b0efd393 Remove possible switch case fall through
Luckily there were no side effects in this... case
2017-06-25 19:09:20 +01:00
Lovell Fuller
df97ef23d9 Document/changelog for Solus Linux support #857 2017-06-25 17:42:03 +01:00
Ekrem Karaca
f6373971bd Add support for Solus OS (#857) 2017-06-24 13:48:03 +01:00
Lovell Fuller
ec617f2489 Document minimum Node dependency of v4.5.0 #847 2017-06-20 22:05:05 +01:00
Lovell Fuller
502ae78579 Allow binary download URL override via SHARP_DIST_BASE_URL #841 2017-06-20 21:40:46 +01:00
Lovell Fuller
49297d6afb Ensure flip and flop operations work with auto-rotate #837 2017-06-19 23:42:26 +01:00
Lovell Fuller
29354badd8 Docs: add Alpine Linux install details 2017-06-19 08:13:49 +01:00
Lovell Fuller
3c4de796c8 Dependency bumps and next point release 2017-06-04 19:55:45 +01:00
Lovell Fuller
c7f4488e77 Docs and changelog entry for #828 2017-06-04 19:51:22 +01:00
Yves Bos
d8765f955d Allow xres and yres to be set for TIFF output (#828) 2017-06-03 10:52:09 +01:00
Lovell Fuller
9f20037dad Release v0.18.1 2017-05-30 21:02:35 +01:00
Lovell Fuller
2ebb090df2 Update Travis CI to Ubuntu 16.04
Rollback Appveyor CI from Node 8 to 7
2017-05-30 20:50:32 +01:00
Lovell Fuller
110fff3ab9 Replace Node 7 with Node 8 in CI environment 2017-05-30 20:32:15 +01:00
Lovell Fuller
f42a1ceab7 Recalculate residual after adjusting shrink #831 2017-05-30 20:22:15 +01:00
Lovell Fuller
9e39a7fa95 Correct shrink calc, regression introduced in e398b47 #831 2017-05-30 17:16:41 +01:00
18 changed files with 235 additions and 38 deletions

View File

@@ -1,21 +1,27 @@
language: node_js
node_js:
- "4"
- "6"
- "7"
os:
- linux
- osx
sudo: false
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
osx_image: xcode8
before_install:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export CXX=g++-4.8; fi
matrix:
include:
- os: linux
dist: trusty
sudo: false
node_js: "4"
- os: linux
dist: trusty
sudo: false
node_js: "6"
- os: linux
dist: trusty
sudo: false
node_js: "8"
- os: osx
osx_image: xcode8
node_js: "4"
- os: osx
osx_image: xcode8
node_js: "6"
- os: osx
osx_image: xcode8
node_js: "8"
after_success:
- npm install coveralls
- cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js

View File

@@ -9,7 +9,7 @@ const got = require('got');
const semver = require('semver');
const tar = require('tar');
const distBaseUrl = 'https://dl.bintray.com/lovell/sharp/';
const distBaseUrl = process.env.SHARP_DIST_BASE_URL || 'https://dl.bintray.com/lovell/sharp/';
// Use NPM-provided environment variable where available, falling back to require-based method for Electron
const minimumLibvipsVersion = process.env.npm_package_config_libvips || require('./package.json').config.libvips;
@@ -73,7 +73,7 @@ module.exports.download_vips = function () {
// Ensure glibc >= 2.15
const lddVersion = process.env.LDD_VERSION;
if (lddVersion) {
if (/(glibc|gnu libc|gentoo)/i.test(lddVersion)) {
if (/(glibc|gnu libc|gentoo|solus)/i.test(lddVersion)) {
const glibcVersion = lddVersion ? lddVersion.split(/\n/)[0].split(' ').slice(-1)[0].trim() : '';
if (glibcVersion && semver.lt(glibcVersion + '.0', '2.13.0')) {
error('glibc version ' + glibcVersion + ' requires manual installation - please see http://sharp.dimens.io/en/stable/install/');

View File

@@ -140,6 +140,8 @@ Use these TIFF options for output image.
- `options.force` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** force TIFF output, otherwise attempt to use input format (optional, default `true`)
- `options.compression` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** compression options: lzw, deflate, jpeg (optional, default `'jpeg'`)
- `options.predictor` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** compression predictor options: none, horizontal, float (optional, default `'none'`)
- `options.xres` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** horizontal resolution in pixels/mm (optional, default `1.0`)
- `options.yres` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** vertical resolution in pixels/mm (optional, default `1.0`)
- `options.squash` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** squash 8-bit images down to 1 bit (optional, default `false`)

View File

@@ -4,6 +4,29 @@
Requires libvips v8.5.5.
#### v0.18.2 - 1<sup>st</sup> July 2017
* Expose libvips' xres and yres properties for TIFF output.
[#828](https://github.com/lovell/sharp/pull/828)
[@YvesBos](https://github.com/YvesBos)
* Ensure flip and flop operations work with auto-rotate.
[#837](https://github.com/lovell/sharp/issues/837)
[@rexxars](https://github.com/rexxars)
* Allow binary download URL override via SHARP_DIST_BASE_URL env variable.
[#841](https://github.com/lovell/sharp/issues/841)
* Add support for Solus Linux.
[#857](https://github.com/lovell/sharp/pull/857)
[@ekremkaraca](https://github.com/ekremkaraca)
#### v0.18.1 - 30<sup>th</sup> May 2017
* Remove regression from #781 that could cause incorrect shrink calculation.
[#831](https://github.com/lovell/sharp/issues/831)
[@suprMax](https://github.com/suprMax)
#### v0.18.0 - 30<sup>th</sup> May 2017
* Remove the previously-deprecated output format "option" functions:

View File

@@ -10,7 +10,7 @@ yarn add sharp
### Prerequisites
* Node v4+
* Node v4.5.0+
* C++11 compatible compiler such as gcc 4.8+, clang 3.0+ or MSVC 2013+
* [node-gyp](https://github.com/TooTallNate/node-gyp#installation) and its dependencies (includes Python)
@@ -32,6 +32,7 @@ Most recent Linux-based operating systems with glibc running on x64 and ARMv6+ C
* Archlinux
* Raspbian Jessie
* Amazon Linux 2016.03, 2016.09
* Solus
To use a globally-installed version of libvips instead of the provided binaries,
make sure it is at least the version listed under `config.libvips` in the `package.json` file
@@ -48,8 +49,17 @@ it is recommended to install a system-wide installation of libvips from source:
https://github.com/jcupitt/libvips#building-libvips-from-a-source-tarball
For Linux-based operating systems such as Alpine that use musl libc,
the smaller stack size means libvips' cache should be disabled
#### Alpine Linux
libvips is available in the
[testing repository](https://pkgs.alpinelinux.org/packages?name=vips-dev):
```sh
apk add vips-dev --update-cache --repository https://dl-3.alpinelinux.org/alpine/edge/testing/
```
The smaller stack size of musl libc means
libvips may need to be used without a cache
via `sharp.cache(false)` to avoid a stack overflow.
### Mac OS
@@ -183,16 +193,27 @@ configuration file to prevent the use of coders known to be vulnerable.
Set the `MAGICK_CONFIGURE_PATH` environment variable
to the directory containing the `policy.xml` file.
### Licences
### Pre-compiled libvips binaries
If a global installation of libvips that meets the
minimum version requirement cannot be found,
this module will download a pre-compiled bundle of libvips
this module will attempt to download a pre-compiled bundle of libvips
and its dependencies on Linux and Windows machines.
Should you need to manually download and inspect these files,
you can do so via https://dl.bintray.com/lovell/sharp/
Should you wish to install these from your own location,
set the `SHARP_DIST_BASE_URL` environment variable, e.g.
```sh
SHARP_DIST_BASE_URL="https://hostname/path/" npm install sharp
```
to use `https://hostname/path/libvips-x.y.z-platform.tar.gz`.
### Licences
This module is licensed under the terms of the
[Apache 2.0 Licence](https://github.com/lovell/sharp/blob/master/LICENSE).

View File

@@ -180,6 +180,8 @@ const Sharp = function (input, options) {
tiffCompression: 'jpeg',
tiffPredictor: 'none',
tiffSquash: false,
tiffXres: 1.0,
tiffYres: 1.0,
tileSize: 256,
tileOverlap: 0,
// Function to notify of libvips warnings

View File

@@ -214,6 +214,8 @@ function webp (options) {
* @param {Boolean} [options.force=true] - force TIFF output, otherwise attempt to use input format
* @param {Boolean} [options.compression='jpeg'] - compression options: lzw, deflate, jpeg
* @param {Boolean} [options.predictor='none'] - compression predictor options: none, horizontal, float
* @param {Number} [options.xres=1.0] - horizontal resolution in pixels/mm
* @param {Number} [options.yres=1.0] - vertical resolution in pixels/mm
* @param {Boolean} [options.squash=false] - squash 8-bit images down to 1 bit
* @returns {Sharp}
* @throws {Error} Invalid options
@@ -233,6 +235,21 @@ function tiff (options) {
throw new Error('Invalid Value for squash ' + options.squash + ' Only Boolean Values allowed for options.squash.');
}
}
// resolution
if (is.object(options) && is.defined(options.xres)) {
if (is.number(options.xres)) {
this.options.tiffXres = options.xres;
} else {
throw new Error('Invalid Value for xres ' + options.xres + ' Only numeric values allowed for options.xres');
}
}
if (is.object(options) && is.defined(options.yres)) {
if (is.number(options.yres)) {
this.options.tiffYres = options.yres;
} else {
throw new Error('Invalid Value for yres ' + options.yres + ' Only numeric values allowed for options.yres');
}
}
// compression
if (is.defined(options) && is.defined(options.compression)) {
if (is.string(options.compression) && is.inArray(options.compression, ['lzw', 'deflate', 'jpeg', 'none'])) {

View File

@@ -1,7 +1,7 @@
{
"name": "sharp",
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images",
"version": "0.18.0",
"version": "0.18.2",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://github.com/lovell/sharp",
"contributors": [
@@ -68,20 +68,20 @@
],
"dependencies": {
"caw": "^2.0.0",
"color": "^1.0.3",
"got": "^7.0.0",
"color": "^2.0.0",
"got": "^7.1.0",
"nan": "^2.6.2",
"semver": "^5.3.0",
"tar": "^3.1.3"
"tar": "^3.1.5"
},
"devDependencies": {
"async": "^2.4.1",
"async": "^2.5.0",
"cc": "^1.0.1",
"documentation": "^4.0.0-rc.1",
"exif-reader": "^1.0.2",
"icc": "^1.0.0",
"mocha": "^3.4.2",
"nyc": "^10.3.2",
"nyc": "^11.0.3",
"rimraf": "^2.6.1",
"semistandard": "^11.0.0",
"unzip": "^0.1.11"
@@ -91,7 +91,7 @@
"libvips": "8.5.5"
},
"engines": {
"node": ">=4"
"node": ">=4.5.0"
},
"semistandard": {
"env": [

View File

@@ -438,9 +438,11 @@ namespace sharp {
// Southeast
left = inWidth - outWidth;
top = inHeight - outHeight;
break;
case 7:
// Southwest
top = inHeight - outHeight;
break;
case 8:
// Northwest
break;

View File

@@ -83,8 +83,11 @@ class PipelineWorker : public Nan::AsyncWorker {
VipsAngle rotation;
if (baton->useExifOrientation) {
// Rotate and flip image according to Exif orientation
// (ignore the requested rotation and flip)
std::tie(rotation, baton->flip, baton->flop) = CalculateExifRotationAndFlip(sharp::ExifOrientation(image));
bool flip;
bool flop;
std::tie(rotation, flip, flop) = CalculateExifRotationAndFlip(sharp::ExifOrientation(image));
baton->flip = baton->flip || flip;
baton->flop = baton->flop || flop;
} else {
rotation = CalculateAngleRotation(baton->angle);
}
@@ -288,11 +291,11 @@ class PipelineWorker : public Nan::AsyncWorker {
}
}
// Help ensure a final kernel-based reduction to prevent shrink aliasing
if ((xshrink > 1 || yshrink > 1) && (xresidual == 1.0 || yresidual == 1.0)) {
if (xshrink > 1 && yshrink > 1 && (xresidual == 1.0 || yresidual == 1.0)) {
xshrink = xshrink / 2;
yshrink = yshrink / 2;
xresidual = xresidual / 2.0;
yresidual = yresidual / 2.0;
xresidual = static_cast<double>(xshrink) / xfactor;
yresidual = static_cast<double>(yshrink) / yfactor;
}
// Ensure we're using a device-independent colour space
@@ -808,7 +811,9 @@ class PipelineWorker : public Nan::AsyncWorker {
->set("Q", baton->tiffQuality)
->set("squash", baton->tiffSquash)
->set("compression", baton->tiffCompression)
->set("predictor", baton->tiffPredictor)));
->set("predictor", baton->tiffPredictor)
->set("xres", baton->tiffXres)
->set("yres", baton->tiffYres)));
baton->bufferOut = static_cast<char*>(area->data);
baton->bufferOutLength = area->length;
area->free_fn = nullptr;
@@ -904,7 +909,9 @@ class PipelineWorker : public Nan::AsyncWorker {
->set("Q", baton->tiffQuality)
->set("squash", baton->tiffSquash)
->set("compression", baton->tiffCompression)
->set("predictor", baton->tiffPredictor));
->set("predictor", baton->tiffPredictor)
->set("xres", baton->tiffXres)
->set("yres", baton->tiffYres));
baton->formatOut = "tiff";
baton->channels = std::min(baton->channels, 3);
} else if (baton->formatOut == "dz" || isDz || isDzZip) {
@@ -1277,6 +1284,8 @@ NAN_METHOD(pipeline) {
baton->webpNearLossless = AttrTo<bool>(options, "webpNearLossless");
baton->tiffQuality = AttrTo<uint32_t>(options, "tiffQuality");
baton->tiffSquash = AttrTo<bool>(options, "tiffSquash");
baton->tiffXres = AttrTo<double>(options, "tiffXres");
baton->tiffYres = AttrTo<double>(options, "tiffYres");
// tiff compression options
baton->tiffCompression = static_cast<VipsForeignTiffCompression>(
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_TIFF_COMPRESSION,

View File

@@ -109,6 +109,8 @@ struct PipelineBaton {
VipsForeignTiffCompression tiffCompression;
VipsForeignTiffPredictor tiffPredictor;
bool tiffSquash;
double tiffXres;
double tiffYres;
std::string err;
bool withMetadata;
int withMetadataOrientation;
@@ -182,6 +184,8 @@ struct PipelineBaton {
tiffCompression(VIPS_FOREIGN_TIFF_COMPRESSION_JPEG),
tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_NONE),
tiffSquash(false),
tiffXres(1.0),
tiffYres(1.0),
withMetadata(false),
withMetadataOrientation(-1),
convKernelWidth(0),

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -933,6 +933,53 @@ describe('Input/output', function () {
});
});
it('TIFF setting xres and yres on file', function (done) {
const res = 1000.0; // inputTiff has a dpi of 300 (res*2.54)
sharp(fixtures.inputTiff)
.tiff({
xres: (res),
yres: (res)
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
sharp(fixtures.outputTiff).metadata(function (err, metadata) {
if (err) throw err;
assert.strictEqual(metadata.density, res * 2.54); // convert to dpi
fs.unlink(fixtures.outputTiff, done);
});
});
});
it('TIFF setting xres and yres on buffer', function (done) {
const res = 1000.0; // inputTiff has a dpi of 300 (res*2.54)
sharp(fixtures.inputTiff)
.tiff({
xres: (res),
yres: (res)
})
.toBuffer(function (err, data, info) {
if (err) throw err;
sharp(data).metadata(function (err, metadata) {
if (err) throw err;
assert.strictEqual(metadata.density, res * 2.54); // convert to dpi
done();
});
});
});
it('TIFF invalid xres value should throw an error', function () {
assert.throws(function () {
sharp().tiff({ xres: '1000.0' });
});
});
it('TIFF invalid yres value should throw an error', function () {
assert.throws(function () {
sharp().tiff({ yres: '1000.0' });
});
});
it('TIFF lzw compression with horizontal predictor shrinks test file', function (done) {
const startSize = fs.statSync(fixtures.inputTiffUncompressed).size;
sharp(fixtures.inputTiffUncompressed)

View File

@@ -412,4 +412,40 @@ describe('Resize dimensions', function () {
sharp().resize(32, 24, { centreSampling: 1 });
});
});
it('Dimensions that result in differing even shrinks on each axis', function (done) {
sharp(fixtures.inputJpg)
.resize(645, 399)
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(645, info.width);
assert.strictEqual(399, info.height);
sharp(data)
.resize(150, 100)
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(150, info.width);
assert.strictEqual(100, info.height);
fixtures.assertSimilar(fixtures.expected('resize-diff-shrink-even.jpg'), data, done);
});
});
});
it('Dimensions that result in differing odd shrinks on each axis', function (done) {
return sharp(fixtures.inputJpg)
.resize(600, 399)
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(600, info.width);
assert.strictEqual(399, info.height);
sharp(data)
.resize(200)
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(200, info.width);
assert.strictEqual(133, info.height);
fixtures.assertSimilar(fixtures.expected('resize-diff-shrink-odd.jpg'), data, done);
});
});
});
});

View File

@@ -253,4 +253,32 @@ describe('Rotation', function () {
fixtures.assertSimilar(fixtures.inputJpg, data, done);
});
});
it('Auto-rotate and flip', function (done) {
sharp(fixtures.inputJpgWithExif)
.rotate()
.flip()
.resize(320)
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(320, info.width);
assert.strictEqual(240, info.height);
fixtures.assertSimilar(fixtures.expected('rotate-and-flip.jpg'), data, done);
});
});
it('Auto-rotate and flop', function (done) {
sharp(fixtures.inputJpgWithExif)
.rotate()
.flop()
.resize(320)
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(320, info.width);
assert.strictEqual(240, info.height);
fixtures.assertSimilar(fixtures.expected('rotate-and-flop.jpg'), data, done);
});
});
});