MCTaylor17
MCTaylor17

Reputation: 429

Serving plain-text SVGs with Express.js (Solution related to Cheerio.js)

I am trying to process SVGs prior to sending them via Express.js. I have the following code:

app.get("/iconic/styles/:style/:base/:icon", function (req, res) {
    var style = req.params.style;
    var base = req.params.base;
    var icon = req.params.icon;

    var iconPath = path.join(iconFolderRoot, style, icon);

    svgProcessor(iconPath, base).then(function (svg) {
        //console.log(svg);  // SO: See the example output posted below

        res.header("Content-Type","image/svg+xml");

        //res.send(new Buffer(svg, 'binary')); // No difference

        res.send(svg);
    }).catch(function (err) {
        res.status(404).send("Error" + JSON.stringify(err, null, "  "));
    });
});

Without setting the res.header(), I can visit the route in the browser and it behaves as expected (scales to fit). Unfortunately, I can't embed them in an <img> tag unless the header is set.

With res.header() set, I can embed the image in an <img> tag, but it doesn't behave as I would expect (static size).

Sending the file directly with res.sendFile(iconPath) works correctly. I wondered if this was because the file needed to be sent as a binary which can be seen in res.send(new Buffer(svg, 'binary')) but this had the same effect as res.send(svg).

The statement console.log(svg) outputs the following code:

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewbox="0 0 128 128" style="enable-background:new 0 0 128 128;" xml:space="preserve">
<style type="text/css">
        .st0{fill:#49C5B1;}
</style>
<title>Icons_TEST</title>
<g id="Example">
        <path {{{REMOVED FOR STACKOVERFLOW POST}}}/>
</g>
</svg>

I can think of a workaround which would be to save the file to a temp directory and using the res.sendFile(tempPath), but there has to be a better way...

Here is a sample of the response header:

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: image/svg+xml
Date: Thu, 20 Oct 2016 00:51:18 GMT
Connection: keep-alive
Content-Length: 3577

Upvotes: 3

Views: 2427

Answers (1)

MCTaylor17
MCTaylor17

Reputation: 429

After posing this question in the Express github page, a user indicated that they were curious about the svgProcessor as a potential problem. Believing that the problem was related to the way it was being served, I tried to eliminate this as a potential cause by rendering the svg directly with res.render(fs.readFileSync(iconPath)). To my surprise, this actually rendered as expected.

I stared at the output from the svgProcessor for a long period of time and couldn't see the difference so I ran it through an online diffing tool and it showed the following:

enter image description here

Even with the answer right in front of me, I still didn't see what the problem was. Then I realized, the B in viewBox was being lower-cased! This was due to a package called Cheerio (which I was using for traversing the svg nodes) normalizing the attributes.

Solution: var $ = cheerio.load(svg, { xmlMode: true } );

Upvotes: 2

Related Questions