svg to png convertion with imagemagick in node.js - node.js

I am search a way in nodejs to convert an svg to png with the help of imagemagick https://github.com/rsms/node-imagemagick, without storing the resulting png in a temp file on the local filesystem.
Unfortunately, I am unable to do this. And I didn't find example in the internet. Can someone give me an example?

var im = require('imagemagick');
var fs = require('fs');
im.convert(['foo.svg', 'png:-'],
function(err, stdout){
if (err) throw err;
//stdout is your image
//just write it to file to test this:
fs.writeFileSync('test.png', stdout,'binary');
});
It just throws the 'raw' arguments to the command line convert, so for any more questions, just look at convert's docs.

oI found what I am looking for. Basically, I figured out how to pipe data into the std::in of the convert execution. This makes it possible for me to convert images without accessing the local file system.
Here is my demo code:
var im = require('imagemagick');
var fs = require('fs');
var svg = fs.readFileSync('/somepath/svg.svg', 'utf8');
var conv = im.convert(['svg:-', 'png:-'])
conv.on('data', function(data) {
console.log('data');
console.log(data);
});
conv.on('end', function() {
console.log('end');
});
conv.stdin.write(svg);
conv.stdin.end();

you can also use streams and pipe the result somewhere without storing the result as a temp file. Below is some sample code take from the github repo
var fs = require('fs');
im.resize({
srcData: fs.readFileSync('kittens.jpg', 'binary'),
width: 256,
format: 'png'
}, function(err, stdout, stderr){
if (err) throw err
fs.writeFileSync('kittens-resized.png', stdout, 'binary'); // change this part
console.log('resized kittens.jpg to fit within 256x256px')
});
btw: your acceptance rate is 0%

You can also use svgexport (I'm its author):
var svgexport = require('svgexport');
svgexport.render({input: 'file.svg', output: 'file.png'}, callback);

Related

Uploading images to SailsJS (via Skipper) and resizing with sharp on stream

I can upload images via skipper and then resize them with sharp but it seems inefficient to me because skipper documentation outlines that file streams can be used for image thumbnailing before file upload.
Can I use sharp module to resize images on the fly? If you provide some example I'll be grateful. Thank you in advance.
With the help of this answer, and this blog post I've finally came up with a solution:
upload: function(req, res) {
var sharp = require('sharp');
var Writable = require('stream').Writable;
var receiver = new Writable({objectMode: true});
receiver._write = function(file, enc, cb) {
var output = require('fs').createWriteStream('./assets/avatar/' + file.fd);
var resizeTransform = sharp().resize(100);
file.pipe(resizeTransform).pipe(output);
cb();
};
req.file('avatar').upload(receiver, (err, files) => {
if (err) {return res.serverError(err);}
return res.ok();
});
}

Writing to file after modifying with cheerio on node

I am running a node script that reads a .svg font file, passes it as a string variable to Cheerio, modifies it and attempts to write to disk
The problem is that although the script seems to work, the output file is identical to the input file, as if no modification happened.
It looks to me as if the original "svgFont" variable that I pass to cheerio is not modified at all.
So I would need to either pass the modifications back to it, or output from cheerio directly to fs write. But I can't see how to.
const cheerio = require('cheerio');
var fs = require('fs');
// read the svg font
fs.readFile('font.svg', function read(err, data) {
if (err) {
throw err;
}
// convert to string and pass to cheerio
var svgFont = data.toString();
const $ = cheerio.load(svgFont, {
normalizeWhitespace: true,
xmlMode: true
});
// loop all glyph tags
$("glyph").each(function(i,el){
// modify things
});
// Finally write the font with the modified paths
fs.writeFile("outFont.svg", svgFont, function(err) {
if(err) {
throw err;
}
console.log("The file was saved!");
});
});
You could use the fs-cheerio package to write to files. In your code the original variable is not being modified. It is the parsed cheerio representation that gets modified.
The right answer is to pass the cheerio object '$' that contains all the modifications using, in this case, .xml(), as this is a .svg file I am reading. For example:
// Finally write the font with the modified paths
fs.writeFile("outFont.svg", $.xml(), function(err) {
if(err) {
throw err;
}
console.log("The file was saved!");
});

nodejs imagemagick how to return text

I'm stuck in the middle of the process of calculating the average color of an image via gm's subclass imagemagick. After resizing the image into a 1x1 image, I need to return the image information by "txt:-" so therefore im using the .out() command of gm. But now I don't know where and how to handle the callback ...
var gm = require('gm').subClass({
imageMagick: true
});
gm(IMAGEPATH).resize('1x1!').out('txt:-').... // how to get the string back ?
i wasn't able to understand it properly let me know if i am wrong
You can try to save response to buffer and then read it's properties like below
var fs = require('fs'),
gm = require('gm').subClass({
imageMagick: true
});
// output all available image properties
gm('20.png').resize(1, 1)
.toBuffer('PNG', function(err, buffer) {
gm(buffer, 'image.png').identify(function(err, data) {
if (!err) console.log(data)
console.log(data)
});
});

Writing buffer response from resemble.js to file

I'm using node-resemble-js to compare two PNG images.
The comparison happens without issue and I get a successful/relevant response however I'm having trouble outputting the image diff.
var express = require('express');
var fs = require('fs');
var resemble = require('node-resemble-js');
var router = express.Router();
router.get('/compare', function(req, res, next) {
compareImages(res);
});
var compareImages = function (res) {
resemble.outputSettings({
largeImageThreshold: 0
});
var diff = resemble('1.png')
.compareTo('2.png')
.ignoreColors()
.onComplete(function(data){
console.log(data);
var png = data.getDiffImage();
fs.writeFile('diff.png', png.data, null, function (err) {
if (err) {
throw 'error writing file: ' + err;
}
console.log('file written');
});
res.render('compare');
});
};
module.exports = router;
It writes to diff.png as expected however it's not creating a valid image.
Any ideas where I'm going wrong? Feel like I'm pretty close but just unsure of final piece.
Thanks
Looks like there is a pack() method that needs to be called, which does some work and then streamifies the data. In that case you can buffer the stream and then call writeFile like this:
var png = data.getDiffImage();
var buf = new Buffer([])
var strm = png.pack()
strm.on('data', function (dat) {
buf = Buffer.concat([buf, dat])
})
strm.on('end', function() {
fs.writeFile('diff.png', buf, null, function (err) {
if (err) {
throw 'error writing file: ' + err;
}
console.log('file written');
})
})
or you can just pipe it like this, which is a little simpler:
png.pack().pipe(fs.createWriteStream('diff.png'))
Honestly, your approach made sense to me (grab the Buffer and write it) but I guess that data Buffer attached to what comes back from getDiffImage isn't really the final png. Seems like the docs are a bit thin but there's some info here: https://github.com/lksv/node-resemble.js/issues/4

Resizing images with Nodejs and Imagemagick

Using nodejs and imagemagick am able to re-size an image and send it to the browser with this.
var http = require('http'),
spawn = require('child_process').spawn;
http.createServer(function(req, res) {
var image = 'test.jpg';
var convert = spawn('convert', [image, '-resize', '100x100', '-']);
convert.stdout.pipe(res);
convert.stderr.pipe(process.stderr);
}).listen(8080);
The test image is read from the file-system, I want to alter so that test image is a binary string.
var image = 'some long binray string representing an image.......';
My plan is to store the binary strings in Mongodb and read them of dynamically.
Take a look at the node module node-imagemagick. There is the following example on the module's page to resize and image and write it to a file...
var fs = require('fs');
im.resize({
srcData: fs.readFileSync('kittens.jpg', 'binary'),
width: 256
}, function(err, stdout, stderr){
if (err) throw err
fs.writeFileSync('kittens-resized.jpg', stdout, 'binary');
console.log('resized kittens.jpg to fit within 256x256px')
});
You can alter this code to do the following...
var mime = require('mime') // Get mime type based on file extension. use "npm install mime"
, fs = require('fs')
, util = require('util')
, http = require('http')
, im = require('imagemagick');
http.createServer(function (req, res) {
var filePath = 'test.jpg';
fs.stat(filePath, function (err, stat) {
if (err) { throw err; }
fs.readFile(filePath, 'binary', function (err, data) {
if (err) { throw err; }
im.resize({
srcData: data,
width: 256
}, function (err, stdout, stderr) {
if (err) { throw err; }
res.writeHead(200, {
'Content-Type': mime.lookup(filePath),
'Content-Length': stat.size
});
var readStream = fs.createReadStream(filePath);
return util.pump(readStream, res);
});
});
});
}).listen(8080);
Ps. Haven't run the code above yet. Will try do it shortly, but it should give you an idea of how to asynchronously resize and stream a file.
Since you are using spawn() to invoke the ImageMagick command line convert, the normal approach is to write intermediate files to a temp directory where they will get cleaned up either immediately after use or as a scheduled/cron job.
If you want to avoid writing the file to convert, one option to try is base64 encoding your images and using the inline format. This is similar to how images are encoded in some HTML emails or web pages.
inline:{base64_file|data:base64_data}
Inline images let you read an image defined in a special base64 encoding.
NOTE: There is a limit on the size of command-line options you can pass .. Imagemagick docs suggest 5000 bytes. Base64-encoded strings are larger than the original (Wikipedia suggests a rough guide of 137% larger) which could be very limiting unless you're showing thumbnails.
Another ImageMagick format option is ephemeral:
ephemeral:{image_file}
Read and then Delete this image file.
If you want to avoid the I/O passing altogether, you would need a Node.js module that directly integrates a low-level library like ImageMagick or GD rather than wrapping command line tools.
What have you tried so far? You can use GridFS to store the image data and retrieve as a stream from there.. This in C#..Not sure if this helps..
public static void UploadPhoto(string name)
{
var server = MongoServer.Create("mongodb://localhost:27017");
var database = server.GetDatabase("MyDB");
string fileName = name;
using (var fs = new FileStream(fileName, FileMode.Open))
{
var gridFsInfo = database.GridFS.Upload(fs, fileName);
var fileId = gridFsInfo.Id;
//ShowPhoto(filename);
}
}
public static Stream ShowPhoto(string name)
{
var server = MongoServer.Create("mongodb://localhost:27017");
var database = server.GetDatabase("MyDB");
var file = database.GridFS.FindOne(Query.EQ("filename",name));
var stream = file.OpenRead())
var bytes = new byte[stream.Length];
stream.Read(bytes,0,(int)stream.Length);
return stream;
}
You can now use the stream returned by ShowPhoto.

Resources