mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 10:30:15 +02:00
Allow xres and yres to be set for TIFF output (#828)
This commit is contained in:
parent
9f20037dad
commit
d8765f955d
@ -180,6 +180,8 @@ const Sharp = function (input, options) {
|
|||||||
tiffCompression: 'jpeg',
|
tiffCompression: 'jpeg',
|
||||||
tiffPredictor: 'none',
|
tiffPredictor: 'none',
|
||||||
tiffSquash: false,
|
tiffSquash: false,
|
||||||
|
tiffXres: 1.0,
|
||||||
|
tiffYres: 1.0,
|
||||||
tileSize: 256,
|
tileSize: 256,
|
||||||
tileOverlap: 0,
|
tileOverlap: 0,
|
||||||
// Function to notify of libvips warnings
|
// Function to notify of libvips warnings
|
||||||
|
@ -214,6 +214,8 @@ function webp (options) {
|
|||||||
* @param {Boolean} [options.force=true] - force TIFF output, otherwise attempt to use input format
|
* @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.compression='jpeg'] - compression options: lzw, deflate, jpeg
|
||||||
* @param {Boolean} [options.predictor='none'] - compression predictor options: none, horizontal, float
|
* @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
|
* @param {Boolean} [options.squash=false] - squash 8-bit images down to 1 bit
|
||||||
* @returns {Sharp}
|
* @returns {Sharp}
|
||||||
* @throws {Error} Invalid options
|
* @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.');
|
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
|
// compression
|
||||||
if (is.defined(options) && is.defined(options.compression)) {
|
if (is.defined(options) && is.defined(options.compression)) {
|
||||||
if (is.string(options.compression) && is.inArray(options.compression, ['lzw', 'deflate', 'jpeg', 'none'])) {
|
if (is.string(options.compression) && is.inArray(options.compression, ['lzw', 'deflate', 'jpeg', 'none'])) {
|
||||||
|
@ -808,7 +808,9 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|||||||
->set("Q", baton->tiffQuality)
|
->set("Q", baton->tiffQuality)
|
||||||
->set("squash", baton->tiffSquash)
|
->set("squash", baton->tiffSquash)
|
||||||
->set("compression", baton->tiffCompression)
|
->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->bufferOut = static_cast<char*>(area->data);
|
||||||
baton->bufferOutLength = area->length;
|
baton->bufferOutLength = area->length;
|
||||||
area->free_fn = nullptr;
|
area->free_fn = nullptr;
|
||||||
@ -904,7 +906,9 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|||||||
->set("Q", baton->tiffQuality)
|
->set("Q", baton->tiffQuality)
|
||||||
->set("squash", baton->tiffSquash)
|
->set("squash", baton->tiffSquash)
|
||||||
->set("compression", baton->tiffCompression)
|
->set("compression", baton->tiffCompression)
|
||||||
->set("predictor", baton->tiffPredictor));
|
->set("predictor", baton->tiffPredictor)
|
||||||
|
->set("xres", baton->tiffXres)
|
||||||
|
->set("yres", baton->tiffYres));
|
||||||
baton->formatOut = "tiff";
|
baton->formatOut = "tiff";
|
||||||
baton->channels = std::min(baton->channels, 3);
|
baton->channels = std::min(baton->channels, 3);
|
||||||
} else if (baton->formatOut == "dz" || isDz || isDzZip) {
|
} else if (baton->formatOut == "dz" || isDz || isDzZip) {
|
||||||
@ -1277,6 +1281,8 @@ NAN_METHOD(pipeline) {
|
|||||||
baton->webpNearLossless = AttrTo<bool>(options, "webpNearLossless");
|
baton->webpNearLossless = AttrTo<bool>(options, "webpNearLossless");
|
||||||
baton->tiffQuality = AttrTo<uint32_t>(options, "tiffQuality");
|
baton->tiffQuality = AttrTo<uint32_t>(options, "tiffQuality");
|
||||||
baton->tiffSquash = AttrTo<bool>(options, "tiffSquash");
|
baton->tiffSquash = AttrTo<bool>(options, "tiffSquash");
|
||||||
|
baton->tiffXres = AttrTo<double>(options, "tiffXres");
|
||||||
|
baton->tiffYres = AttrTo<double>(options, "tiffYres");
|
||||||
// tiff compression options
|
// tiff compression options
|
||||||
baton->tiffCompression = static_cast<VipsForeignTiffCompression>(
|
baton->tiffCompression = static_cast<VipsForeignTiffCompression>(
|
||||||
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_TIFF_COMPRESSION,
|
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_TIFF_COMPRESSION,
|
||||||
|
@ -109,6 +109,8 @@ struct PipelineBaton {
|
|||||||
VipsForeignTiffCompression tiffCompression;
|
VipsForeignTiffCompression tiffCompression;
|
||||||
VipsForeignTiffPredictor tiffPredictor;
|
VipsForeignTiffPredictor tiffPredictor;
|
||||||
bool tiffSquash;
|
bool tiffSquash;
|
||||||
|
double tiffXres;
|
||||||
|
double tiffYres;
|
||||||
std::string err;
|
std::string err;
|
||||||
bool withMetadata;
|
bool withMetadata;
|
||||||
int withMetadataOrientation;
|
int withMetadataOrientation;
|
||||||
@ -182,6 +184,8 @@ struct PipelineBaton {
|
|||||||
tiffCompression(VIPS_FOREIGN_TIFF_COMPRESSION_JPEG),
|
tiffCompression(VIPS_FOREIGN_TIFF_COMPRESSION_JPEG),
|
||||||
tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_NONE),
|
tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_NONE),
|
||||||
tiffSquash(false),
|
tiffSquash(false),
|
||||||
|
tiffXres(1.0),
|
||||||
|
tiffYres(1.0),
|
||||||
withMetadata(false),
|
withMetadata(false),
|
||||||
withMetadataOrientation(-1),
|
withMetadataOrientation(-1),
|
||||||
convKernelWidth(0),
|
convKernelWidth(0),
|
||||||
|
@ -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) {
|
it('TIFF lzw compression with horizontal predictor shrinks test file', function (done) {
|
||||||
const startSize = fs.statSync(fixtures.inputTiffUncompressed).size;
|
const startSize = fs.statSync(fixtures.inputTiffUncompressed).size;
|
||||||
sharp(fixtures.inputTiffUncompressed)
|
sharp(fixtures.inputTiffUncompressed)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user