@@ -14,7 +14,7 @@ const version_id = 'dev',
1414
1515/** @summary version date
1616 * @desc Release date in format day/month/year like '14/04/2022' */
17- version_date = '30/01 /2026',
17+ version_date = '2/02 /2026',
1818
1919/** @summary version id and date
2020 * @desc Produced by concatenation of {@link version_id} and {@link version_date}
@@ -257,6 +257,8 @@ settings = {
257257 Render3DBatch: constants$1.Render3D.Default,
258258 /** @summary Way to embed 3D drawing in SVG, see {@link constants.Embed3D} for possible values */
259259 Embed3D: constants$1.Embed3D.Default,
260+ /** @summary Use `resvg-js` backend for converting SVGs in node.js */
261+ UseResvgJs: true,
260262 /** @summary Default canvas width */
261263 CanvasWidth: 1200,
262264 /** @summary Default canvas height */
@@ -965,11 +967,12 @@ function findFunction(name) {
965967
966968/** @summary Method to create http request, without promise can be used only in browser environment
967969 * @private */
968- function createHttpRequest(url, kind, user_accept_callback, user_reject_callback, use_promise) {
970+ function createHttpRequest(url, kind, user_accept_callback, user_reject_callback, use_promise, tmout ) {
969971 function configureXhr(xhr) {
970972 xhr.http_callback = isFunc(user_accept_callback) ? user_accept_callback.bind(xhr) : () => {};
971973 xhr.error_callback = isFunc(user_reject_callback) ? user_reject_callback.bind(xhr) : function(err) {
972- console.warn(err.message);
974+ if (err?.message)
975+ console.warn(err.message);
973976 this.http_callback(null);
974977 }.bind(xhr);
975978
@@ -1079,6 +1082,15 @@ function createHttpRequest(url, kind, user_accept_callback, user_reject_callback
10791082 xhr.responseType = 'arraybuffer';
10801083 }
10811084
1085+ if (tmout && Number.isFinite(tmout)) {
1086+ xhr.timeout = tmout;
1087+ xhr.ontimeout = function() {
1088+ this.did_abort = true;
1089+ this.abort();
1090+ this.error_callback(Error(`Request ${url} timeout`));
1091+ };
1092+ }
1093+
10821094 return xhr;
10831095 }
10841096
@@ -9601,7 +9613,8 @@ async function svgToImage(svg, image_format, args) {
96019613 return internals.makePDF ? internals.makePDF(svg, args) : null;
96029614
96039615 // required with df104.py/df105.py example with RCanvas or any special symbols in TLatex
9604- const doctype = '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">';
9616+ const doctype = '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">',
9617+ is_rgba = image_format === 'rgba';
96059618
96069619 if (isNodeJs()) {
96079620 svg = encodeURIComponent(doctype + svg);
@@ -9612,6 +9625,31 @@ async function svgToImage(svg, image_format, args) {
96129625
96139626 const img_src = 'data:image/svg+xml;base64,' + btoa_func(decodeURIComponent(svg));
96149627
9628+ // Use the newer and stabler `resvg-js` backend for converting SVG to PNG
9629+ if (settings.UseResvgJs) {
9630+ return Promise.resolve().then(function () { return index; }).then(({ Resvg }) => {
9631+ const rawSvg = decodeURIComponent(svg), // raw SVG XML
9632+ resvg = new Resvg(rawSvg), // Initialize Resvg and create the PNG buffer
9633+ renderData = resvg.render(),
9634+ pngBuffer = renderData.asPng();
9635+
9636+ // Return raw RGBA pixels if caller requested it
9637+ if (is_rgba) {
9638+ return {
9639+ width: renderData.width,
9640+ height: renderData.height,
9641+ data: renderData.pixels
9642+ };
9643+ }
9644+
9645+ if (args?.as_buffer)
9646+ return pngBuffer;
9647+
9648+ return 'data:image/png;base64,' + pngBuffer.toString('base64');
9649+ });
9650+ }
9651+
9652+ // Fallback to `node-canvas`
96159653 return Promise.resolve().then(function () { return _rollup_plugin_ignore_empty_module_placeholder$1; }).then(async handle => {
96169654 return handle.default.loadImage(img_src).then(img => {
96179655 const canvas = handle.default.createCanvas(img.width, img.height);
@@ -9621,7 +9659,7 @@ async function svgToImage(svg, image_format, args) {
96219659 if (args?.as_buffer)
96229660 return canvas.toBuffer('image/' + image_format);
96239661
9624- return image_format ? canvas.toDataURL('image/' + image_format) : canvas;
9662+ return image_format && !is_rgba ? canvas.toDataURL('image/' + image_format) : canvas;
96259663 });
96269664 });
96279665 }
@@ -9643,7 +9681,7 @@ async function svgToImage(svg, image_format, args) {
96439681 if (args?.as_buffer && image_format)
96449682 canvas.toBlob(blob => blob.arrayBuffer().then(resolveFunc), 'image/' + image_format);
96459683 else
9646- resolveFunc(image_format ? canvas.toDataURL('image/' + image_format) : canvas);
9684+ resolveFunc(image_format && !is_rgba ? canvas.toDataURL('image/' + image_format) : canvas);
96479685 };
96489686 image.onerror = function(arg) {
96499687 URL.revokeObjectURL(img_src);
@@ -91245,18 +91283,26 @@ class TPavePainter extends ObjectPainter {
9124591283 tm = pad?.fTopMargin ?? gStyle.fPadTopMargin,
9124691284 bm = pad?.fBottomMargin ?? gStyle.fPadBottomMargin;
9124791285
91248- return svgToImage(svg_code).then(canvas => {
91249- if (!canvas)
91286+ return svgToImage(svg_code, 'rgba').then(image => {
91287+ if (!image)
91288+ return false;
91289+
91290+ let arr = image.data;
91291+ const width = image.width, height = image.height;
91292+
91293+ if (!arr && isFunc(image.getContext) && image.getContext('2d'))
91294+ arr = image.getContext('2d').getImageData(0, 0, width, height).data;
91295+
91296+ if (!arr)
9125091297 return false;
9125191298
9125291299 let nX = 100, nY = 100;
91253- const context = canvas.getContext('2d'),
91254- arr = context.getImageData(0, 0, canvas.width, canvas.height).data,
91255- boxW = Math.floor(canvas.width / nX), boxH = Math.floor(canvas.height / nY),
91300+ const boxW = Math.floor(width / nX),
91301+ boxH = Math.floor(height / nY),
9125691302 raster = new Array(nX * nY);
9125791303
91258- if (arr.length !== canvas. width * canvas. height * 4) {
91259- console.log(`Image size missmatch in TLegend autoplace ${arr.length} expected ${canvas. width * canvas. height * 4}`);
91304+ if (arr.length !== width * height * 4) {
91305+ console.log(`Image size missmatch in TLegend autoplace ${arr.length} expected ${width * height * 4}`);
9126091306 nX = nY = 0;
9126191307 }
9126291308
@@ -91268,7 +91314,7 @@ class TPavePainter extends ObjectPainter {
9126891314
9126991315 for (let x = px1; (x < px2) && !filled; ++x) {
9127091316 for (let y = py1; y < py2; ++y) {
91271- const indx = (y * canvas. width + x) * 4;
91317+ const indx = (y * width + x) * 4;
9127291318 if (arr[indx] || arr[indx + 1] || arr[indx + 2] || arr[indx + 3]) {
9127391319 filled = 1;
9127491320 break;
@@ -168594,6 +168640,34 @@ __proto__: null,
168594168640default: _rollup_plugin_ignore_empty_module_placeholder
168595168641});
168596168642
168643+ const { render: _render, renderAsync: _renderAsync, Resvg: _Resvg } = require('./js-binding.js');
168644+
168645+ module.exports.render = function render(svg, options) {
168646+ if (options) {
168647+ return _render(svg, JSON.stringify(options))
168648+ }
168649+ return _render(svg)
168650+ };
168651+
168652+ module.exports.renderAsync = function renderAsync(svg, options, signal) {
168653+ if (options) {
168654+ return _renderAsync(svg, JSON.stringify(options), signal)
168655+ }
168656+ return _renderAsync(svg, null, signal)
168657+ };
168658+
168659+ module.exports.Resvg = class Resvg extends _Resvg {
168660+ constructor(svg, options) {
168661+ super(svg, JSON.stringify(options));
168662+ }
168663+ };
168664+
168665+ // module.exports.Resvg = _Resvg
168666+
168667+ var index = /*#__PURE__*/Object.freeze({
168668+ __proto__: null
168669+ });
168670+
168597168671/** @summary Draw TEllipse
168598168672 * @private */
168599168673function drawEllipse() {
0 commit comments