diff --git a/docs/api-composite.md b/docs/api-composite.md index aff46029..03c65485 100644 --- a/docs/api-composite.md +++ b/docs/api-composite.md @@ -18,7 +18,7 @@ If the overlay image contains an alpha channel then composition with premultipli - `options.left` **[Number][4]?** the pixel offset from the left edge. - `options.tile` **[Boolean][5]** set to true to repeat the overlay image across the entire image with the given `gravity`. (optional, default `false`) - `options.cutout` **[Boolean][5]** set to true to apply only the alpha channel of the overlay image to the input image, giving the appearance of one image being cut out of another. (optional, default `false`) - - `options.density` **[Number][4]** integral number representing the DPI for vector overlay image. (optional, default `72`) + - `options.density` **[Number][4]** number representing the DPI for vector overlay image. (optional, default `72`) - `options.raw` **[Object][3]?** describes overlay when using raw pixel data. - `options.raw.width` **[Number][4]?** - `options.raw.height` **[Number][4]?** diff --git a/docs/api-constructor.md b/docs/api-constructor.md index 140d3c7c..94d917ff 100644 --- a/docs/api-constructor.md +++ b/docs/api-constructor.md @@ -12,7 +12,7 @@ - `options.failOnError` **[Boolean][4]** by default apply a "best effort" to decode images, even if the data is corrupt or invalid. Set this flag to true if you'd rather halt processing and raise an error when loading invalid images. (optional, default `false`) - - `options.density` **[Number][5]** integral number representing the DPI for vector images. (optional, default `72`) + - `options.density` **[Number][5]** number representing the DPI for vector images. (optional, default `72`) - `options.page` **[Number][5]** page number to extract for multi-page input (GIF, TIFF) (optional, default `0`) - `options.raw` **[Object][3]?** describes raw pixel input image data. See `raw()` for pixel ordering. - `options.raw.width` **[Number][5]?** diff --git a/lib/composite.js b/lib/composite.js index 1dc95c43..82e0e78d 100644 --- a/lib/composite.js +++ b/lib/composite.js @@ -34,7 +34,7 @@ const is = require('./is'); * @param {Number} [options.left] - the pixel offset from the left edge. * @param {Boolean} [options.tile=false] - set to true to repeat the overlay image across the entire image with the given `gravity`. * @param {Boolean} [options.cutout=false] - set to true to apply only the alpha channel of the overlay image to the input image, giving the appearance of one image being cut out of another. - * @param {Number} [options.density=72] - integral number representing the DPI for vector overlay image. + * @param {Number} [options.density=72] - number representing the DPI for vector overlay image. * @param {Object} [options.raw] - describes overlay when using raw pixel data. * @param {Number} [options.raw.width] * @param {Number} [options.raw.height] diff --git a/lib/constructor.js b/lib/constructor.js index 20afa476..463da8de 100644 --- a/lib/constructor.js +++ b/lib/constructor.js @@ -96,7 +96,7 @@ const debuglog = util.debuglog('sharp'); * @param {Boolean} [options.failOnError=false] - by default apply a "best effort" * to decode images, even if the data is corrupt or invalid. Set this flag to true * if you'd rather halt processing and raise an error when loading invalid images. - * @param {Number} [options.density=72] - integral number representing the DPI for vector images. + * @param {Number} [options.density=72] - number representing the DPI for vector images. * @param {Number} [options.page=0] - page number to extract for multi-page input (GIF, TIFF) * @param {Object} [options.raw] - describes raw pixel input image data. See `raw()` for pixel ordering. * @param {Number} [options.raw.width] diff --git a/lib/input.js b/lib/input.js index 041f7a42..bcc2a18c 100644 --- a/lib/input.js +++ b/lib/input.js @@ -36,7 +36,7 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { } // Density if (is.defined(inputOptions.density)) { - if (is.integer(inputOptions.density) && is.inRange(inputOptions.density, 1, 2400)) { + if (is.inRange(inputOptions.density, 1, 2400)) { inputDescriptor.density = inputOptions.density; } else { throw new Error('Invalid density (1 to 2400) ' + inputOptions.density); diff --git a/src/common.cc b/src/common.cc index 543f80b8..6d82d04d 100644 --- a/src/common.cc +++ b/src/common.cc @@ -55,7 +55,7 @@ namespace sharp { descriptor->failOnError = AttrTo(input, "failOnError"); // Density for vector-based input if (HasAttr(input, "density")) { - descriptor->density = AttrTo(input, "density"); + descriptor->density = AttrTo(input, "density"); } // Raw pixel input if (HasAttr(input, "rawChannels")) { @@ -228,7 +228,7 @@ namespace sharp { ->set("access", accessMethod) ->set("fail", descriptor->failOnError); if (imageType == ImageType::SVG || imageType == ImageType::PDF) { - option->set("dpi", static_cast(descriptor->density)); + option->set("dpi", descriptor->density); } if (imageType == ImageType::MAGICK) { option->set("density", std::to_string(descriptor->density).data()); @@ -270,7 +270,7 @@ namespace sharp { ->set("access", accessMethod) ->set("fail", descriptor->failOnError); if (imageType == ImageType::SVG || imageType == ImageType::PDF) { - option->set("dpi", static_cast(descriptor->density)); + option->set("dpi", descriptor->density); } if (imageType == ImageType::MAGICK) { option->set("density", std::to_string(descriptor->density).data()); @@ -355,8 +355,8 @@ namespace sharp { /* Set pixels/mm resolution based on a pixels/inch density. */ - void SetDensity(VImage image, const int density) { - const double pixelsPerMm = static_cast(density) / 25.4; + void SetDensity(VImage image, const double density) { + const double pixelsPerMm = density / 25.4; image.set("Xres", pixelsPerMm); image.set("Yres", pixelsPerMm); image.set(VIPS_META_RESOLUTION_UNIT, "in"); diff --git a/src/common.h b/src/common.h index 6a788f10..5ac1cf13 100644 --- a/src/common.h +++ b/src/common.h @@ -49,7 +49,7 @@ namespace sharp { char *buffer; bool failOnError; size_t bufferLength; - int density; + double density; int rawChannels; int rawWidth; int rawHeight; @@ -63,7 +63,7 @@ namespace sharp { buffer(nullptr), failOnError(FALSE), bufferLength(0), - density(72), + density(72.0), rawChannels(0), rawWidth(0), rawHeight(0), @@ -186,7 +186,7 @@ namespace sharp { /* Set pixels/mm resolution based on a pixels/inch density. */ - void SetDensity(VImage image, const int density); + void SetDensity(VImage image, const double density); /* Check the proposed format supports the current dimensions. diff --git a/test/fixtures/expected/svg14.4.png b/test/fixtures/expected/svg14.4.png new file mode 100644 index 00000000..32f2fb3d Binary files /dev/null and b/test/fixtures/expected/svg14.4.png differ diff --git a/test/unit/io.js b/test/unit/io.js index 61462c46..8c5f0fb3 100644 --- a/test/unit/io.js +++ b/test/unit/io.js @@ -939,6 +939,21 @@ describe('Input/output', function () { }); }); + it('Convert SVG to PNG at 14.4DPI', function (done) { + sharp(fixtures.inputSvg, { density: 14.4 }) + .toFormat('png') + .toBuffer(function (err, data, info) { + if (err) throw err; + assert.strictEqual('png', info.format); + assert.strictEqual(20, info.width); + assert.strictEqual(20, info.height); + fixtures.assertSimilar(fixtures.expected('svg14.4.png'), data, function (err) { + if (err) throw err; + done(); + }); + }); + }); + it('Convert SVG with embedded images to PNG, respecting dimensions, autoconvert to PNG', function (done) { sharp(fixtures.inputSvgWithEmbeddedImages) .toBuffer(function (err, data, info) { @@ -1506,11 +1521,6 @@ describe('Input/output', function () { sharp(null, { density: 'zoinks' }); }); }); - it('Invalid density: float', function () { - assert.throws(function () { - sharp(null, { density: 0.5 }); - }); - }); it('Ignore unknown attribute', function () { sharp(null, { unknown: true }); });