Compare commits

..

10 Commits

Author SHA1 Message Date
Lovell Fuller
d5ecc537af Release v0.24.1 2020-02-15 13:48:46 +00:00
Lovell Fuller
c7a49054fd Docs: update libvips URLs for band format/interpretation 2020-02-15 13:43:47 +00:00
Lovell Fuller
a2314c4aa0 Ensure RGBA LZW TIFF info.channel count #2064 2020-02-15 11:46:13 +00:00
Lovell Fuller
1717173f17 Tests: tighten composite offset thresholds 2020-02-15 10:53:30 +00:00
Lovell Fuller
e44c12f029 Bump dependencies, tar is now node>=10 2020-02-15 10:53:00 +00:00
Lovell Fuller
1a98c390fc Prevent sequentialRead for EXIF-based rotate op #2042 2020-01-20 21:50:43 +00:00
Lovell Fuller
91902740e4 Attempt to detect out-of-date homebrew-managed vips 2020-01-19 19:58:24 +00:00
Lovell Fuller
6aa6a93b44 Docs: add details of ignore-scripts to installation guide 2020-01-19 19:27:50 +00:00
Lovell Fuller
b4135ac9b3 Docs: fix any remaining redirects 2020-01-16 20:57:02 +00:00
Lovell Fuller
78906e6551 Update any remaining documentation links 2020-01-16 20:52:19 +00:00
17 changed files with 94 additions and 23 deletions

View File

@@ -7,7 +7,7 @@ assignees: ''
--- ---
Did you see the [documentation relating to installation](https://sharp.pixelplumbing.com/en/stable/install/)? Did you see the [documentation relating to installation](https://sharp.pixelplumbing.com/install)?
Have you ensured the platform and version of Node.js used for `npm install` is the same as the platform and version of Node.js used at runtime? Have you ensured the platform and version of Node.js used for `npm install` is the same as the platform and version of Node.js used at runtime?

View File

@@ -90,10 +90,10 @@ readableStream
### Documentation ### Documentation
Visit [sharp.pixelplumbing.com](https://sharp.pixelplumbing.com/) for complete Visit [sharp.pixelplumbing.com](https://sharp.pixelplumbing.com/) for complete
[installation instructions](https://sharp.pixelplumbing.com/page/install), [installation instructions](https://sharp.pixelplumbing.com/install),
[API documentation](https://sharp.pixelplumbing.com/page/api), [API documentation](https://sharp.pixelplumbing.com/api-constructor),
[benchmark tests](https://sharp.pixelplumbing.com/page/performance) and [benchmark tests](https://sharp.pixelplumbing.com/performance) and
[changelog](https://sharp.pixelplumbing.com/page/changelog). [changelog](https://sharp.pixelplumbing.com/changelog).
### Contributing ### Contributing

View File

@@ -88,9 +88,9 @@ image
Returns **[Promise][5]<[Object][6]>** Returns **[Promise][5]<[Object][6]>**
[1]: https://github.com/libvips/libvips/blob/master/libvips/iofuncs/enumtypes.c#L636 [1]: https://libvips.github.io/libvips/API/current/VipsImage.html#VipsInterpretation
[2]: https://github.com/libvips/libvips/blob/master/libvips/iofuncs/enumtypes.c#L672 [2]: https://libvips.github.io/libvips/API/current/VipsImage.html#VipsBandFormat
[3]: https://www.npmjs.com/package/icc [3]: https://www.npmjs.com/package/icc

View File

@@ -4,6 +4,14 @@
Requires libvips v8.9.0. Requires libvips v8.9.0.
### v0.24.1 - 15<sup>th</sup> February 2020
* Prevent use of sequentialRead for EXIF-based rotate operation.
[#2042](https://github.com/lovell/sharp/issues/2042)
* Ensure RGBA LZW TIFF returns correct channel count.
[#2064](https://github.com/lovell/sharp/issues/2064)
### v0.24.0 - 16<sup>th</sup> January 2020 ### v0.24.0 - 16<sup>th</sup> January 2020
* Drop support for Node.js 8. * Drop support for Node.js 8.

View File

@@ -25,6 +25,11 @@
"destination": "/install", "destination": "/install",
"type": 301 "type": 301
}, },
{
"source": "/page/install",
"destination": "/install",
"type": 301
},
{ {
"source": "**/api-constructor/**", "source": "**/api-constructor/**",
"destination": "/api-constructor", "destination": "/api-constructor",
@@ -70,16 +75,31 @@
"destination": "/api-utility", "destination": "/api-utility",
"type": 301 "type": 301
}, },
{
"source": "/page/api",
"destination": "/api-constructor",
"type": 301
},
{ {
"source": "**/performance/**", "source": "**/performance/**",
"destination": "/performance", "destination": "/performance",
"type": 301 "type": 301
}, },
{
"source": "/page/performance",
"destination": "/performance",
"type": 301
},
{ {
"source": "**/changelog/**", "source": "**/changelog/**",
"destination": "/changelog", "destination": "/changelog",
"type": 301 "type": 301
}, },
{
"source": "/page/changelog",
"destination": "/changelog",
"type": 301
},
{ {
"source": "/en/**", "source": "/en/**",
"destination": "/", "destination": "/",

View File

@@ -62,7 +62,7 @@
docuteGoogleAnalytics('UA-13034748-12'), docuteGoogleAnalytics('UA-13034748-12'),
docuteApiTitlePlugin docuteApiTitlePlugin
], ],
sourcePath: 'https://cdn.jsdelivr.net/gh/lovell/sharp@v0.24.0/docs', sourcePath: 'https://cdn.jsdelivr.net/gh/lovell/sharp@v0.24.1/docs',
nav: [ nav: [
{ {
title: 'Funding', title: 'Funding',

View File

@@ -54,6 +54,8 @@ must be the same as the platform and major version of Node.js used at runtime.
The `npm install --unsafe-perm` flag must be used when installing as `root` or a `sudo` user. The `npm install --unsafe-perm` flag must be used when installing as `root` or a `sudo` user.
The `npm install --ignore-scripts=false` flag must be used when `npm` has been configured to ignore installation scripts.
Check the output of running `npm install --verbose sharp` for useful error messages. Check the output of running `npm install --verbose sharp` for useful error messages.
## Custom libvips ## Custom libvips

View File

@@ -16,6 +16,8 @@ try {
help.push('- Ensure the version of Node.js used at install time matches that used at runtime'); help.push('- Ensure the version of Node.js used at install time matches that used at runtime');
} else if (/invalid ELF header/.test(err.message)) { } else if (/invalid ELF header/.test(err.message)) {
help.push(`- Ensure "${process.platform}" is used at install time as well as runtime`); help.push(`- Ensure "${process.platform}" is used at install time as well as runtime`);
} else if (/dylib/.test(err.message) && /Incompatible library version/.test(err.message)) {
help.push('- Run "brew update && brew upgrade vips"');
} else if (/Cannot find module/.test(err.message)) { } else if (/Cannot find module/.test(err.message)) {
help.push('- Run "npm rebuild --verbose sharp" and look for errors'); help.push('- Run "npm rebuild --verbose sharp" and look for errors');
} else { } else {

View File

@@ -187,9 +187,9 @@ function _isStreamInput () {
* - `size`: Total size of image in bytes, for Stream and Buffer input only * - `size`: Total size of image in bytes, for Stream and Buffer input only
* - `width`: Number of pixels wide (EXIF orientation is not taken into consideration) * - `width`: Number of pixels wide (EXIF orientation is not taken into consideration)
* - `height`: Number of pixels high (EXIF orientation is not taken into consideration) * - `height`: Number of pixels high (EXIF orientation is not taken into consideration)
* - `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.com/libvips/libvips/blob/master/libvips/iofuncs/enumtypes.c#L636) * - `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://libvips.github.io/libvips/API/current/VipsImage.html#VipsInterpretation)
* - `channels`: Number of bands e.g. `3` for sRGB, `4` for CMYK * - `channels`: Number of bands e.g. `3` for sRGB, `4` for CMYK
* - `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://github.com/libvips/libvips/blob/master/libvips/iofuncs/enumtypes.c#L672) * - `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://libvips.github.io/libvips/API/current/VipsImage.html#VipsBandFormat)
* - `density`: Number of pixels per inch (DPI), if present * - `density`: Number of pixels per inch (DPI), if present
* - `chromaSubsampling`: String containing JPEG chroma subsampling, `4:2:0` or `4:4:4` for RGB, `4:2:0:4` or `4:4:4:4` for CMYK * - `chromaSubsampling`: String containing JPEG chroma subsampling, `4:2:0` or `4:4:4` for RGB, `4:2:0:4` or `4:4:4:4` for CMYK
* - `isProgressive`: Boolean indicating whether the image is interlaced using a progressive scan * - `isProgressive`: Boolean indicating whether the image is interlaced using a progressive scan

View File

@@ -1,7 +1,7 @@
{ {
"name": "sharp", "name": "sharp",
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images", "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images",
"version": "0.24.0", "version": "0.24.1",
"author": "Lovell Fuller <npm@lovell.info>", "author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://github.com/lovell/sharp", "homepage": "https://github.com/lovell/sharp",
"contributors": [ "contributors": [
@@ -112,25 +112,25 @@
"nan": "^2.14.0", "nan": "^2.14.0",
"npmlog": "^4.1.2", "npmlog": "^4.1.2",
"prebuild-install": "^5.3.3", "prebuild-install": "^5.3.3",
"semver": "^7.1.1", "semver": "^7.1.3",
"simple-get": "^3.1.0", "simple-get": "^3.1.0",
"tar": "^5.0.5", "tar": "^6.0.1",
"tunnel-agent": "^0.6.0" "tunnel-agent": "^0.6.0"
}, },
"devDependencies": { "devDependencies": {
"async": "^3.1.0", "async": "^3.1.1",
"cc": "^2.0.1", "cc": "^2.0.1",
"decompress-zip": "^0.3.2", "decompress-zip": "^0.3.2",
"documentation": "^12.1.4", "documentation": "^12.1.4",
"exif-reader": "^1.0.3", "exif-reader": "^1.0.3",
"icc": "^1.0.0", "icc": "^1.0.0",
"license-checker": "^25.0.1", "license-checker": "^25.0.1",
"mocha": "^7.0.0", "mocha": "^7.0.1",
"mock-fs": "^4.10.4", "mock-fs": "^4.10.4",
"nyc": "^15.0.0", "nyc": "^15.0.0",
"prebuild": "^10.0.0", "prebuild": "^10.0.0",
"prebuild-ci": "^3.1.0", "prebuild-ci": "^3.1.0",
"rimraf": "^3.0.0", "rimraf": "^3.0.2",
"semistandard": "^14.2.0" "semistandard": "^14.2.0"
}, },
"license": "Apache-2.0", "license": "Apache-2.0",

View File

@@ -764,6 +764,7 @@ class PipelineWorker : public Nan::AsyncWorker {
// Write TIFF to buffer // Write TIFF to buffer
if (baton->tiffCompression == VIPS_FOREIGN_TIFF_COMPRESSION_JPEG) { if (baton->tiffCompression == VIPS_FOREIGN_TIFF_COMPRESSION_JPEG) {
sharp::AssertImageTypeDimensions(image, ImageType::JPEG); sharp::AssertImageTypeDimensions(image, ImageType::JPEG);
baton->channels = std::min(baton->channels, 3);
} }
// Cast pixel values to float, if required // Cast pixel values to float, if required
if (baton->tiffPredictor == VIPS_FOREIGN_TIFF_PREDICTOR_FLOAT) { if (baton->tiffPredictor == VIPS_FOREIGN_TIFF_PREDICTOR_FLOAT) {
@@ -786,7 +787,6 @@ class PipelineWorker : public Nan::AsyncWorker {
area->free_fn = nullptr; area->free_fn = nullptr;
vips_area_unref(area); vips_area_unref(area);
baton->formatOut = "tiff"; baton->formatOut = "tiff";
baton->channels = std::min(baton->channels, 3);
} else if (baton->formatOut == "heif" || (baton->formatOut == "input" && inputImageType == ImageType::HEIF)) { } else if (baton->formatOut == "heif" || (baton->formatOut == "input" && inputImageType == ImageType::HEIF)) {
// Write HEIF to buffer // Write HEIF to buffer
VipsArea *area = VIPS_AREA(image.heifsave_buffer(VImage::option() VipsArea *area = VIPS_AREA(image.heifsave_buffer(VImage::option()
@@ -887,6 +887,7 @@ class PipelineWorker : public Nan::AsyncWorker {
// Write TIFF to file // Write TIFF to file
if (baton->tiffCompression == VIPS_FOREIGN_TIFF_COMPRESSION_JPEG) { if (baton->tiffCompression == VIPS_FOREIGN_TIFF_COMPRESSION_JPEG) {
sharp::AssertImageTypeDimensions(image, ImageType::JPEG); sharp::AssertImageTypeDimensions(image, ImageType::JPEG);
baton->channels = std::min(baton->channels, 3);
} }
image.tiffsave(const_cast<char*>(baton->fileOut.data()), VImage::option() image.tiffsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
->set("strip", !baton->withMetadata) ->set("strip", !baton->withMetadata)
@@ -901,7 +902,6 @@ class PipelineWorker : public Nan::AsyncWorker {
->set("xres", baton->tiffXres) ->set("xres", baton->tiffXres)
->set("yres", baton->tiffYres)); ->set("yres", baton->tiffYres));
baton->formatOut = "tiff"; baton->formatOut = "tiff";
baton->channels = std::min(baton->channels, 3);
} else if (baton->formatOut == "heif" || (mightMatchInput && isHeif) || } else if (baton->formatOut == "heif" || (mightMatchInput && isHeif) ||
(willMatchInput && inputImageType == ImageType::HEIF)) { (willMatchInput && inputImageType == ImageType::HEIF)) {
// Write HEIF to file // Write HEIF to file
@@ -1404,7 +1404,9 @@ NAN_METHOD(pipeline) {
baton->trimThreshold > 0.0 || baton->trimThreshold > 0.0 ||
baton->normalise || baton->normalise ||
baton->position == 16 || baton->position == 17 || baton->position == 16 || baton->position == 17 ||
baton->angle != 0 || baton->rotationAngle != 0.0 baton->angle % 360 != 0 ||
fmod(baton->rotationAngle, 360.0) != 0.0 ||
baton->useExifOrientation
) { ) {
baton->input->access = VIPS_ACCESS_RANDOM; baton->input->access = VIPS_ACCESS_RANDOM;
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -141,7 +141,7 @@ describe('composite', () => {
it('zero offset', done => { it('zero offset', done => {
sharp(fixtures.inputJpg) sharp(fixtures.inputJpg)
.resize(400) .resize(80)
.composite([{ .composite([{
input: fixtures.inputPngWithTransparency16bit, input: fixtures.inputPngWithTransparency16bit,
top: 0, top: 0,
@@ -157,7 +157,7 @@ describe('composite', () => {
it('offset and gravity', done => { it('offset and gravity', done => {
sharp(fixtures.inputJpg) sharp(fixtures.inputJpg)
.resize(400) .resize(80)
.composite([{ .composite([{
input: fixtures.inputPngWithTransparency16bit, input: fixtures.inputPngWithTransparency16bit,
left: 10, left: 10,
@@ -174,7 +174,7 @@ describe('composite', () => {
it('offset, gravity and tile', done => { it('offset, gravity and tile', done => {
sharp(fixtures.inputJpg) sharp(fixtures.inputJpg)
.resize(400) .resize(80)
.composite([{ .composite([{
input: fixtures.inputPngWithTransparency16bit, input: fixtures.inputPngWithTransparency16bit,
left: 10, left: 10,
@@ -192,7 +192,7 @@ describe('composite', () => {
it('offset and tile', done => { it('offset and tile', done => {
sharp(fixtures.inputJpg) sharp(fixtures.inputJpg)
.resize(400) .resize(80)
.composite([{ .composite([{
input: fixtures.inputPngWithTransparency16bit, input: fixtures.inputPngWithTransparency16bit,
left: 10, left: 10,

View File

@@ -208,11 +208,48 @@ describe('TIFF', function () {
.toFile(fixtures.outputTiff, (err, info) => { .toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err; if (err) throw err;
assert.strictEqual('tiff', info.format); assert.strictEqual('tiff', info.format);
assert.strictEqual(3, info.channels);
assert(info.size < startSize); assert(info.size < startSize);
rimraf(fixtures.outputTiff, done); rimraf(fixtures.outputTiff, done);
}); });
}); });
it('TIFF LZW RGBA toFile', () =>
sharp({
create: {
width: 1,
height: 1,
channels: 4,
background: 'red'
}
})
.tiff({
compression: 'lzw'
})
.toFile(fixtures.outputTiff)
.then(info => {
assert.strictEqual(4, info.channels);
})
);
it('TIFF LZW RGBA toBuffer', () =>
sharp({
create: {
width: 1,
height: 1,
channels: 4,
background: 'red'
}
})
.tiff({
compression: 'lzw'
})
.toBuffer({ resolveWithObject: true })
.then(({ info }) => {
assert.strictEqual(4, info.channels);
})
);
it('TIFF ccittfax4 compression shrinks b-w test file', function (done) { it('TIFF ccittfax4 compression shrinks b-w test file', function (done) {
const startSize = fs.statSync(fixtures.inputTiff).size; const startSize = fs.statSync(fixtures.inputTiff).size;
sharp(fixtures.inputTiff) sharp(fixtures.inputTiff)