mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 10:30:15 +02:00
Expose stylesheet and highBitdepth SVG input params
This commit is contained in:
parent
f92540f134
commit
c4b1d80c35
@ -80,6 +80,9 @@ where the overall height is the `pageHeight` multiplied by the number of `pages`
|
|||||||
| [options.join.valign] | <code>string</code> | <code>"'top'"</code> | vertical alignment style for images joined vertically (`'top'`, `'centre'`, `'center'`, `'bottom'`). |
|
| [options.join.valign] | <code>string</code> | <code>"'top'"</code> | vertical alignment style for images joined vertically (`'top'`, `'centre'`, `'center'`, `'bottom'`). |
|
||||||
| [options.tiff] | <code>Object</code> | | Describes TIFF specific options. |
|
| [options.tiff] | <code>Object</code> | | Describes TIFF specific options. |
|
||||||
| [options.tiff.subifd] | <code>number</code> | <code>-1</code> | Sub Image File Directory to extract for OME-TIFF, defaults to main image. |
|
| [options.tiff.subifd] | <code>number</code> | <code>-1</code> | Sub Image File Directory to extract for OME-TIFF, defaults to main image. |
|
||||||
|
| [options.svg] | <code>Object</code> | | Describes SVG specific options. |
|
||||||
|
| [options.svg.stylesheet] | <code>string</code> | | Custom CSS for SVG input, applied with a User Origin during the CSS cascade. |
|
||||||
|
| [options.svg.highBitdepth] | <code>boolean</code> | <code>false</code> | Set to `true` to render SVG input at 32-bits per channel (128-bit) instead of 8-bits per channel (32-bit) RGBA. |
|
||||||
| [options.pdf] | <code>Object</code> | | Describes PDF specific options. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. |
|
| [options.pdf] | <code>Object</code> | | Describes PDF specific options. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. |
|
||||||
| [options.pdf.background] | <code>string</code> \| <code>Object</code> | | Background colour to use when PDF is partially transparent. Parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. |
|
| [options.pdf.background] | <code>string</code> \| <code>Object</code> | | Background colour to use when PDF is partially transparent. Parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. |
|
||||||
| [options.openSlide] | <code>Object</code> | | Describes OpenSlide specific options. Requires the use of a globally-installed libvips compiled with support for OpenSlide. |
|
| [options.openSlide] | <code>Object</code> | | Describes OpenSlide specific options. Requires the use of a globally-installed libvips compiled with support for OpenSlide. |
|
||||||
|
@ -14,6 +14,8 @@ Requires libvips v8.17.0
|
|||||||
|
|
||||||
* Deprecate top-level, format-specific constructor parameters, e.g. `subifd` becomes `tiff.subifd`.
|
* Deprecate top-level, format-specific constructor parameters, e.g. `subifd` becomes `tiff.subifd`.
|
||||||
|
|
||||||
|
* Expose `stylesheet` and `highBitdepth` SVG input parameters.
|
||||||
|
|
||||||
* Expose `keepDuplicateFrames` GIF output parameter.
|
* Expose `keepDuplicateFrames` GIF output parameter.
|
||||||
|
|
||||||
* Expose JPEG 2000 `oneshot` decoder option.
|
* Expose JPEG 2000 `oneshot` decoder option.
|
||||||
|
@ -190,6 +190,9 @@ const debuglog = util.debuglog('sharp');
|
|||||||
* @param {string} [options.join.valign='top'] - vertical alignment style for images joined vertically (`'top'`, `'centre'`, `'center'`, `'bottom'`).
|
* @param {string} [options.join.valign='top'] - vertical alignment style for images joined vertically (`'top'`, `'centre'`, `'center'`, `'bottom'`).
|
||||||
* @param {Object} [options.tiff] - Describes TIFF specific options.
|
* @param {Object} [options.tiff] - Describes TIFF specific options.
|
||||||
* @param {number} [options.tiff.subifd=-1] - Sub Image File Directory to extract for OME-TIFF, defaults to main image.
|
* @param {number} [options.tiff.subifd=-1] - Sub Image File Directory to extract for OME-TIFF, defaults to main image.
|
||||||
|
* @param {Object} [options.svg] - Describes SVG specific options.
|
||||||
|
* @param {string} [options.svg.stylesheet] - Custom CSS for SVG input, applied with a User Origin during the CSS cascade.
|
||||||
|
* @param {boolean} [options.svg.highBitdepth=false] - Set to `true` to render SVG input at 32-bits per channel (128-bit) instead of 8-bits per channel (32-bit) RGBA.
|
||||||
* @param {Object} [options.pdf] - Describes PDF specific options. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick.
|
* @param {Object} [options.pdf] - Describes PDF specific options. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick.
|
||||||
* @param {string|Object} [options.pdf.background] - Background colour to use when PDF is partially transparent. Parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.
|
* @param {string|Object} [options.pdf.background] - Background colour to use when PDF is partially transparent. Parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.
|
||||||
* @param {Object} [options.openSlide] - Describes OpenSlide specific options. Requires the use of a globally-installed libvips compiled with support for OpenSlide.
|
* @param {Object} [options.openSlide] - Describes OpenSlide specific options. Requires the use of a globally-installed libvips compiled with support for OpenSlide.
|
||||||
|
9
lib/index.d.ts
vendored
9
lib/index.d.ts
vendored
@ -1005,6 +1005,8 @@ declare namespace sharp {
|
|||||||
page?: number | undefined;
|
page?: number | undefined;
|
||||||
/** TIFF specific input options */
|
/** TIFF specific input options */
|
||||||
tiff?: TiffInputOptions | undefined;
|
tiff?: TiffInputOptions | undefined;
|
||||||
|
/** SVG specific input options */
|
||||||
|
svg?: SvgInputOptions | undefined;
|
||||||
/** PDF specific input options */
|
/** PDF specific input options */
|
||||||
pdf?: PdfInputOptions | undefined;
|
pdf?: PdfInputOptions | undefined;
|
||||||
/** OpenSlide specific input options */
|
/** OpenSlide specific input options */
|
||||||
@ -1127,6 +1129,13 @@ declare namespace sharp {
|
|||||||
subifd?: number | undefined;
|
subifd?: number | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SvgInputOptions {
|
||||||
|
/** Custom CSS for SVG input, applied with a User Origin during the CSS cascade. */
|
||||||
|
stylesheet?: string | undefined;
|
||||||
|
/** Set to `true` to render SVG input at 32-bits per channel (128-bit) instead of 8-bits per channel (32-bit) RGBA. */
|
||||||
|
highBitdepth?: boolean | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
interface PdfInputOptions {
|
interface PdfInputOptions {
|
||||||
/** Background colour to use when PDF is partially transparent. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. */
|
/** Background colour to use when PDF is partially transparent. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. */
|
||||||
background?: Colour | Color | undefined;
|
background?: Colour | Color | undefined;
|
||||||
|
36
lib/input.js
36
lib/input.js
@ -22,14 +22,27 @@ const align = {
|
|||||||
high: 'high'
|
high: 'high'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const inputStreamParameters = [
|
||||||
|
// Limits and error handling
|
||||||
|
'failOn', 'limitInputPixels', 'unlimited',
|
||||||
|
// Format-generic
|
||||||
|
'animated', 'autoOrient', 'density', 'ignoreIcc', 'page', 'pages', 'sequentialRead',
|
||||||
|
// Format-specific
|
||||||
|
'jp2', 'openSlide', 'pdf', 'raw', 'svg', 'tiff',
|
||||||
|
// Deprecated
|
||||||
|
'failOnError', 'level', 'pdfBackground', 'subifd'
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract input options, if any, from an object.
|
* Extract input options, if any, from an object.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
function _inputOptionsFromObject (obj) {
|
function _inputOptionsFromObject (obj) {
|
||||||
const { raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd, pdfBackground, autoOrient, jp2Oneshot } = obj;
|
const params = inputStreamParameters
|
||||||
return [raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd, pdfBackground, autoOrient, jp2Oneshot].some(is.defined)
|
.filter(p => is.defined(obj[p]))
|
||||||
? { raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd, pdfBackground, autoOrient, jp2Oneshot }
|
.map(p => ([p, obj[p]]));
|
||||||
|
return params.length
|
||||||
|
? Object.fromEntries(params)
|
||||||
: undefined;
|
: undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,6 +273,23 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|||||||
throw is.invalidParameterError('subifd', 'integer between -1 and 100000', inputOptions.subifd);
|
throw is.invalidParameterError('subifd', 'integer between -1 and 100000', inputOptions.subifd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// SVG specific options
|
||||||
|
if (is.object(inputOptions.svg)) {
|
||||||
|
if (is.defined(inputOptions.svg.stylesheet)) {
|
||||||
|
if (is.string(inputOptions.svg.stylesheet)) {
|
||||||
|
inputDescriptor.svgStylesheet = inputOptions.svg.stylesheet;
|
||||||
|
} else {
|
||||||
|
throw is.invalidParameterError('svg.stylesheet', 'string', inputOptions.svg.stylesheet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is.defined(inputOptions.svg.highBitdepth)) {
|
||||||
|
if (is.bool(inputOptions.svg.highBitdepth)) {
|
||||||
|
inputDescriptor.svgHighBitdepth = inputOptions.svg.highBitdepth;
|
||||||
|
} else {
|
||||||
|
throw is.invalidParameterError('svg.highBitdepth', 'boolean', inputOptions.svg.highBitdepth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// PDF specific options
|
// PDF specific options
|
||||||
if (is.object(inputOptions.pdf) && is.defined(inputOptions.pdf.background)) {
|
if (is.object(inputOptions.pdf) && is.defined(inputOptions.pdf.background)) {
|
||||||
inputDescriptor.pdfBackground = this._getBackgroundColourOption(inputOptions.pdf.background);
|
inputDescriptor.pdfBackground = this._getBackgroundColourOption(inputOptions.pdf.background);
|
||||||
|
@ -101,6 +101,13 @@ namespace sharp {
|
|||||||
if (HasAttr(input, "page")) {
|
if (HasAttr(input, "page")) {
|
||||||
descriptor->page = AttrAsUint32(input, "page");
|
descriptor->page = AttrAsUint32(input, "page");
|
||||||
}
|
}
|
||||||
|
// SVG
|
||||||
|
if (HasAttr(input, "svgStylesheet")) {
|
||||||
|
descriptor->svgStylesheet = AttrAsStr(input, "svgStylesheet");
|
||||||
|
}
|
||||||
|
if (HasAttr(input, "svgHighBitdepth")) {
|
||||||
|
descriptor->svgHighBitdepth = AttrAsBool(input, "svgHighBitdepth");
|
||||||
|
}
|
||||||
// Multi-level input (OpenSlide)
|
// Multi-level input (OpenSlide)
|
||||||
if (HasAttr(input, "level")) {
|
if (HasAttr(input, "level")) {
|
||||||
descriptor->level = AttrAsUint32(input, "level");
|
descriptor->level = AttrAsUint32(input, "level");
|
||||||
@ -429,6 +436,10 @@ namespace sharp {
|
|||||||
option->set("n", descriptor->pages);
|
option->set("n", descriptor->pages);
|
||||||
option->set("page", descriptor->page);
|
option->set("page", descriptor->page);
|
||||||
}
|
}
|
||||||
|
if (imageType == ImageType::SVG) {
|
||||||
|
option->set("stylesheet", descriptor->svgStylesheet.data());
|
||||||
|
option->set("high_bitdepth", descriptor->svgHighBitdepth);
|
||||||
|
}
|
||||||
if (imageType == ImageType::OPENSLIDE) {
|
if (imageType == ImageType::OPENSLIDE) {
|
||||||
option->set("level", descriptor->level);
|
option->set("level", descriptor->level);
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,8 @@ namespace sharp {
|
|||||||
std::vector<double> joinBackground;
|
std::vector<double> joinBackground;
|
||||||
VipsAlign joinHalign;
|
VipsAlign joinHalign;
|
||||||
VipsAlign joinValign;
|
VipsAlign joinValign;
|
||||||
|
std::string svgStylesheet;
|
||||||
|
bool svgHighBitdepth;
|
||||||
std::vector<double> pdfBackground;
|
std::vector<double> pdfBackground;
|
||||||
bool jp2Oneshot;
|
bool jp2Oneshot;
|
||||||
|
|
||||||
@ -121,6 +123,7 @@ namespace sharp {
|
|||||||
joinBackground{ 0.0, 0.0, 0.0, 255.0 },
|
joinBackground{ 0.0, 0.0, 0.0, 255.0 },
|
||||||
joinHalign(VIPS_ALIGN_LOW),
|
joinHalign(VIPS_ALIGN_LOW),
|
||||||
joinValign(VIPS_ALIGN_LOW),
|
joinValign(VIPS_ALIGN_LOW),
|
||||||
|
svgHighBitdepth(false),
|
||||||
pdfBackground{ 255.0, 255.0, 255.0, 255.0 },
|
pdfBackground{ 255.0, 255.0, 255.0, 255.0 },
|
||||||
jp2Oneshot(false) {}
|
jp2Oneshot(false) {}
|
||||||
};
|
};
|
||||||
|
@ -730,6 +730,9 @@ sharp({ openSlide: { level: 0 } });
|
|||||||
sharp({ level: 0 }); // Deprecated
|
sharp({ level: 0 }); // Deprecated
|
||||||
sharp({ jp2: { oneshot: true } });
|
sharp({ jp2: { oneshot: true } });
|
||||||
sharp({ jp2: { oneshot: false } });
|
sharp({ jp2: { oneshot: false } });
|
||||||
|
sharp({ svg: { stylesheet: 'test' }});
|
||||||
|
sharp({ svg: { highBitdepth: true }});
|
||||||
|
sharp({ svg: { highBitdepth: false }});
|
||||||
|
|
||||||
sharp({ autoOrient: true });
|
sharp({ autoOrient: true });
|
||||||
sharp({ autoOrient: false });
|
sharp({ autoOrient: false });
|
||||||
|
@ -139,6 +139,41 @@ describe('SVG input', function () {
|
|||||||
assert.strictEqual(info.channels, 4);
|
assert.strictEqual(info.channels, 4);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Can apply custom CSS', async () => {
|
||||||
|
const svg = `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="10" height="10" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="5" cy="5" r="4" fill="green" />
|
||||||
|
</svg>`;
|
||||||
|
const stylesheet = 'circle { fill: red }';
|
||||||
|
|
||||||
|
const [r, g, b, a] = await sharp(Buffer.from(svg), { svg: { stylesheet } })
|
||||||
|
.extract({ left: 5, top: 5, width: 1, height: 1 })
|
||||||
|
.raw()
|
||||||
|
.toBuffer();
|
||||||
|
|
||||||
|
assert.deepEqual([r, g, b, a], [255, 0, 0, 255]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Invalid stylesheet input option throws', () =>
|
||||||
|
assert.throws(
|
||||||
|
() => sharp({ svg: { stylesheet: 123 } }),
|
||||||
|
/Expected string for svg\.stylesheet but received 123 of type number/
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
it('Valid highBitdepth input option does not throw', () =>
|
||||||
|
assert.doesNotThrow(
|
||||||
|
() => sharp({ svg: { highBitdepth: true } })
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
it('Invalid highBitdepth input option throws', () =>
|
||||||
|
assert.throws(
|
||||||
|
() => sharp({ svg: { highBitdepth: 123 } }),
|
||||||
|
/Expected boolean for svg\.highBitdepth but received 123 of type number/
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
it('Fails to render SVG larger than 32767x32767', () =>
|
it('Fails to render SVG larger than 32767x32767', () =>
|
||||||
assert.rejects(
|
assert.rejects(
|
||||||
() => sharp(Buffer.from('<svg xmlns="http://www.w3.org/2000/svg" width="32768" height="1" />')).toBuffer(),
|
() => sharp(Buffer.from('<svg xmlns="http://www.w3.org/2000/svg" width="32768" height="1" />')).toBuffer(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user