mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 10:30:15 +02:00
Expose libvips pyramid/tile options for TIFF output (#1483)
This commit is contained in:
parent
fd1ca1dbb2
commit
c695c40abc
@ -177,7 +177,11 @@ const Sharp = function (input, options) {
|
||||
tiffQuality: 80,
|
||||
tiffCompression: 'jpeg',
|
||||
tiffPredictor: 'horizontal',
|
||||
tiffPyramid: false,
|
||||
tiffSquash: false,
|
||||
tiffTile: false,
|
||||
tiffTileHeight: 256,
|
||||
tiffTileWidth: 256,
|
||||
tiffXres: 1.0,
|
||||
tiffYres: 1.0,
|
||||
tileSize: 256,
|
||||
|
@ -304,6 +304,10 @@ 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, ccittfax4
|
||||
* @param {Boolean} [options.predictor='horizontal'] - compression predictor options: none, horizontal, float
|
||||
* @param {Boolean} [options.pyramid=false] - write an image pyramid
|
||||
* @param {Boolean} [options.tile=false] - write a tiled tiff
|
||||
* @param {Boolean} [options.tileWidth=256] - horizontal tile size
|
||||
* @param {Boolean} [options.tileHeight=256] - vertical tile size
|
||||
* @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
|
||||
@ -311,29 +315,60 @@ function webp (options) {
|
||||
* @throws {Error} Invalid options
|
||||
*/
|
||||
function tiff (options) {
|
||||
if (is.object(options) && is.defined(options.quality)) {
|
||||
if (is.object(options)) {
|
||||
if (is.defined(options.quality)) {
|
||||
if (is.integer(options.quality) && is.inRange(options.quality, 1, 100)) {
|
||||
this.options.tiffQuality = options.quality;
|
||||
} else {
|
||||
throw new Error('Invalid quality (integer, 1-100) ' + options.quality);
|
||||
}
|
||||
}
|
||||
if (is.object(options) && is.defined(options.squash)) {
|
||||
if (is.defined(options.squash)) {
|
||||
if (is.bool(options.squash)) {
|
||||
this.options.tiffSquash = options.squash;
|
||||
} else {
|
||||
throw new Error('Invalid Value for squash ' + options.squash + ' Only Boolean Values allowed for options.squash.');
|
||||
}
|
||||
}
|
||||
// tiling
|
||||
if (is.defined(options.tile)) {
|
||||
if (is.bool(options.tile)) {
|
||||
this.options.tiffTile = options.tile;
|
||||
} else {
|
||||
throw new Error('Invalid Value for tile ' + options.tile + ' Only Boolean values allowed for options.tile');
|
||||
}
|
||||
}
|
||||
if (is.defined(options.tileWidth)) {
|
||||
if (is.number(options.tileWidth) && options.tileWidth > 0) {
|
||||
this.options.tiffTileWidth = options.tileWidth;
|
||||
} else {
|
||||
throw new Error('Invalid Value for tileWidth ' + options.tileWidth + ' Only positive numeric values allowed for options.tileWidth');
|
||||
}
|
||||
}
|
||||
if (is.defined(options.tileHeight)) {
|
||||
if (is.number(options.tileHeight) && options.tileHeight > 0) {
|
||||
this.options.tiffTileHeight = options.tileHeight;
|
||||
} else {
|
||||
throw new Error('Invalid Value for tileHeight ' + options.tileHeight + ' Only positive numeric values allowed for options.tileHeight');
|
||||
}
|
||||
}
|
||||
// pyramid
|
||||
if (is.defined(options.pyramid)) {
|
||||
if (is.bool(options.pyramid)) {
|
||||
this.options.tiffPyramid = options.pyramid;
|
||||
} else {
|
||||
throw new Error('Invalid Value for pyramid ' + options.pyramid + ' Only Boolean values allowed for options.pyramid');
|
||||
}
|
||||
}
|
||||
// resolution
|
||||
if (is.object(options) && is.defined(options.xres)) {
|
||||
if (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.defined(options.yres)) {
|
||||
if (is.number(options.yres)) {
|
||||
this.options.tiffYres = options.yres;
|
||||
} else {
|
||||
@ -341,7 +376,7 @@ function tiff (options) {
|
||||
}
|
||||
}
|
||||
// compression
|
||||
if (is.defined(options) && is.defined(options.compression)) {
|
||||
if (is.defined(options.compression)) {
|
||||
if (is.string(options.compression) && is.inArray(options.compression, ['lzw', 'deflate', 'jpeg', 'ccittfax4', 'none'])) {
|
||||
this.options.tiffCompression = options.compression;
|
||||
} else {
|
||||
@ -350,7 +385,7 @@ function tiff (options) {
|
||||
}
|
||||
}
|
||||
// predictor
|
||||
if (is.defined(options) && is.defined(options.predictor)) {
|
||||
if (is.defined(options.predictor)) {
|
||||
if (is.string(options.predictor) && is.inArray(options.predictor, ['none', 'horizontal', 'float'])) {
|
||||
this.options.tiffPredictor = options.predictor;
|
||||
} else {
|
||||
@ -358,6 +393,7 @@ function tiff (options) {
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this._updateFormatOut('tiff', options);
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,8 @@
|
||||
"Freezy <freezy@xbmc.org>",
|
||||
"Daiz <taneli.vatanen@gmail.com>",
|
||||
"Julian Aubourg <j@ubourg.net>",
|
||||
"Keith Belovay <keith@picthrive.com>"
|
||||
"Keith Belovay <keith@picthrive.com>",
|
||||
"Michael B. Klein <mbklein@gmail.com>"
|
||||
],
|
||||
"scripts": {
|
||||
"install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)",
|
||||
|
@ -763,6 +763,10 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
->set("squash", baton->tiffSquash)
|
||||
->set("compression", baton->tiffCompression)
|
||||
->set("predictor", baton->tiffPredictor)
|
||||
->set("pyramid", baton->tiffPyramid)
|
||||
->set("tile", baton->tiffTile)
|
||||
->set("tile_height", baton->tiffTileHeight)
|
||||
->set("tile_width", baton->tiffTileWidth)
|
||||
->set("xres", baton->tiffXres)
|
||||
->set("yres", baton->tiffYres)));
|
||||
baton->bufferOut = static_cast<char*>(area->data);
|
||||
@ -862,6 +866,10 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
->set("squash", baton->tiffSquash)
|
||||
->set("compression", baton->tiffCompression)
|
||||
->set("predictor", baton->tiffPredictor)
|
||||
->set("pyramid", baton->tiffPyramid)
|
||||
->set("tile", baton->tiffTile)
|
||||
->set("tile_height", baton->tiffTileHeight)
|
||||
->set("tile_width", baton->tiffTileWidth)
|
||||
->set("xres", baton->tiffXres)
|
||||
->set("yres", baton->tiffYres));
|
||||
baton->formatOut = "tiff";
|
||||
@ -1272,7 +1280,11 @@ NAN_METHOD(pipeline) {
|
||||
baton->webpLossless = AttrTo<bool>(options, "webpLossless");
|
||||
baton->webpNearLossless = AttrTo<bool>(options, "webpNearLossless");
|
||||
baton->tiffQuality = AttrTo<uint32_t>(options, "tiffQuality");
|
||||
baton->tiffPyramid = AttrTo<bool>(options, "tiffPyramid");
|
||||
baton->tiffSquash = AttrTo<bool>(options, "tiffSquash");
|
||||
baton->tiffTile = AttrTo<bool>(options, "tiffTile");
|
||||
baton->tiffTileWidth = AttrTo<uint32_t>(options, "tiffTileWidth");
|
||||
baton->tiffTileHeight = AttrTo<uint32_t>(options, "tiffTileHeight");
|
||||
baton->tiffXres = AttrTo<double>(options, "tiffXres");
|
||||
baton->tiffYres = AttrTo<double>(options, "tiffYres");
|
||||
// tiff compression options
|
||||
|
@ -122,7 +122,11 @@ struct PipelineBaton {
|
||||
int tiffQuality;
|
||||
VipsForeignTiffCompression tiffCompression;
|
||||
VipsForeignTiffPredictor tiffPredictor;
|
||||
bool tiffPyramid;
|
||||
bool tiffSquash;
|
||||
bool tiffTile;
|
||||
int tiffTileHeight;
|
||||
int tiffTileWidth;
|
||||
double tiffXres;
|
||||
double tiffYres;
|
||||
std::string err;
|
||||
@ -215,7 +219,11 @@ struct PipelineBaton {
|
||||
tiffQuality(80),
|
||||
tiffCompression(VIPS_FOREIGN_TIFF_COMPRESSION_JPEG),
|
||||
tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL),
|
||||
tiffPyramid(false),
|
||||
tiffSquash(false),
|
||||
tiffTile(false),
|
||||
tiffTileHeight(256),
|
||||
tiffTileWidth(256),
|
||||
tiffXres(1.0),
|
||||
tiffYres(1.0),
|
||||
withMetadata(false),
|
||||
|
@ -1285,6 +1285,84 @@ describe('Input/output', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('TIFF tiled pyramid image without compression enlarges test file', function (done) {
|
||||
const startSize = fs.statSync(fixtures.inputTiffUncompressed).size;
|
||||
sharp(fixtures.inputTiffUncompressed)
|
||||
.tiff({
|
||||
compression: 'none',
|
||||
pyramid: true,
|
||||
tile: true,
|
||||
tileHeight: 256,
|
||||
tileWidth: 256
|
||||
})
|
||||
.toFile(fixtures.outputTiff, (err, info) => {
|
||||
if (err) throw err;
|
||||
assert.strictEqual('tiff', info.format);
|
||||
assert(info.size > startSize);
|
||||
rimraf(fixtures.outputTiff, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('TIFF pyramid true value does not throw error', function () {
|
||||
assert.doesNotThrow(function () {
|
||||
sharp().tiff({ pyramid: true });
|
||||
});
|
||||
});
|
||||
|
||||
it('Invalid TIFF pyramid value throws error', function () {
|
||||
assert.throws(function () {
|
||||
sharp().tiff({ pyramid: 'true' });
|
||||
});
|
||||
});
|
||||
|
||||
it('Invalid TIFF tile value throws error', function () {
|
||||
assert.throws(function () {
|
||||
sharp().tiff({ tile: 'true' });
|
||||
});
|
||||
});
|
||||
|
||||
it('TIFF tile true value does not throw error', function () {
|
||||
assert.doesNotThrow(function () {
|
||||
sharp().tiff({ tile: true });
|
||||
});
|
||||
});
|
||||
|
||||
it('Valid TIFF tileHeight value does not throw error', function () {
|
||||
assert.doesNotThrow(function () {
|
||||
sharp().tiff({ tileHeight: 512 });
|
||||
});
|
||||
});
|
||||
|
||||
it('Valid TIFF tileWidth value does not throw error', function () {
|
||||
assert.doesNotThrow(function () {
|
||||
sharp().tiff({ tileWidth: 512 });
|
||||
});
|
||||
});
|
||||
|
||||
it('Invalid TIFF tileHeight value throws error', function () {
|
||||
assert.throws(function () {
|
||||
sharp().tiff({ tileHeight: '256' });
|
||||
});
|
||||
});
|
||||
|
||||
it('Invalid TIFF tileWidth value throws error', function () {
|
||||
assert.throws(function () {
|
||||
sharp().tiff({ tileWidth: '256' });
|
||||
});
|
||||
});
|
||||
|
||||
it('Invalid TIFF tileHeight value throws error', function () {
|
||||
assert.throws(function () {
|
||||
sharp().tiff({ tileHeight: 0 });
|
||||
});
|
||||
});
|
||||
|
||||
it('Invalid TIFF tileWidth value throws error', function () {
|
||||
assert.throws(function () {
|
||||
sharp().tiff({ tileWidth: 0 });
|
||||
});
|
||||
});
|
||||
|
||||
it('Input and output formats match when not forcing', function (done) {
|
||||
sharp(fixtures.inputJpg)
|
||||
.resize(320, 240)
|
||||
|
Loading…
x
Reference in New Issue
Block a user