Resizing images with Nodejs and Imagemagick - node.js

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.

Related

Getting image size from Imgur link in discord.js [duplicate]

I am trying to load the dimensions of an image from url. So far I've tried using GraphicsMagick but it gives me ENOENT error.
Here's the code so far I've written.
var gm = require('gm');
...
gm(img.attribs.src).size(function (err, size) {
if (!err) {
if( size.width>200 && size.height>200)
{
console.log('Save this image');
}
}
});
Where img.attribs.src contains the url source path of the image.
Update
value of img.attribs.src
http://rack.1.mshcdn.com/assets/header_logo.v2-30574d105ad07318345ec8f1a85a3efa.png
https://github.com/nodeca/probe-image-size it does exactly you asked about, without heavy dependencies. Also, it downloads only necessary peace of files.
Example:
var probe = require('probe-image-size');
probe('http://example.com/image.jpg', function (err, result) {
console.log(result);
// => {
// width: xx,
// height: yy,
// type: 'jpg',
// mime: 'image/jpeg',
// wUnits: 'px',
// hUnits: 'px'
// }
});
Disclaimer: I am the author of this package.
What you want to do is to download the file first. The easiest way is to use request module. The cool thing is that both request and gm can use streams. The only thing you need to remember when working with streams and gm's identify commands (like size, format, etc) you need to set bufferStream option to true. More info here.
var gm = require('gm');
var request = require('request');
var url = "http://strabo.com/gallery/albums/wallpaper/foo_wallpaper.sized.jpg";
var stream = request(url);
gm(stream, './img.jpg').size({ bufferStream: true }, function (err, size) {
if (err) { throw err; }
console.log(size);
});
You could also download file on disk (using request as well) an then use gm as normal.
I've used this library to perform the operation successfully.
You need the image-size NPM, this work fine at my end hope work at your
var sizeOf = require('image-size');
sizeOf('/images/'+adsImage, function (err, dimensions) {
var imgwidth= dimensions.width;
var imgheight= dimensions.height;
console.log(imgheight +" = = = = "+imgwidth)
if( imgwidth>200 && imgheight>200)
{
console.log('Save this image');
}
});

Pipe image through graphics magic only half complete

I am trying to set up a transform stream to pipe an image through with GM https://github.com/aheckmann/gm. So I can do something like:
readStream.pipe(resize()).pipe(writeStream);
I have used through2 along with gm to try and achieve this. It works but only parses half the image, leaving a large portion just grey.
'use strict';
var fs = require('fs')
, gm = require('gm').subClass({imageMagick: true})
, through2 = require('through2');
let readStream = fs.createReadStream('landscape.jpg');
let writeStream = fs.createWriteStream('landscape-out.jpg');
let resize = function(width, height) {
return through2(function(chunk, enc, callback){
gm(chunk)
.resize(800)
.gravity('Center')
.crop(800, 500, 0, 0)
.stream((err, stdout, stderr) => {
stdout.on('data', chunk => {
this.push(chunk);
});
stdout.on('end', () => {
callback();
});
});
});
}
readStream.pipe(resize()).pipe(writeStream);
In
through2(function(chunk, enc, callback){
chunk is only a small part of the image.
So the behavior you got seems normal, you are resizing the chunks of the image, not the image itself.
This said, in the doc,
// GOTCHA:
// when working with input streams and any 'identify'
// operation (size, format, etc), you must pass "{bufferStream: true}" if
// you also need to convert (write() or stream()) the image afterwards
// NOTE: this buffers the readStream in memory!
var readStream = fs.createReadStream('/path/to/my/img.jpg');
gm(readStream)
.size({bufferStream: true}, function(err, size) {
this.resize(size.width / 2, size.height / 2)
this.write('/path/to/resized.jpg', function (err) {
if (!err) console.log('done');
});
});
but it s going to buffer the picture in memory, so it s not optimum.
As you are using imagemagick, you shall just let it manage all that part of the processing. And later fs.readStream, the output.
From the doc
var writeStream = fs.createWriteStream('/path/to/my/reformatted.png');
gm('/path/to/my/img.jpg')
.stream('png')
.pipe(writeStream);

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

Get image dimensions from url path

I am trying to load the dimensions of an image from url. So far I've tried using GraphicsMagick but it gives me ENOENT error.
Here's the code so far I've written.
var gm = require('gm');
...
gm(img.attribs.src).size(function (err, size) {
if (!err) {
if( size.width>200 && size.height>200)
{
console.log('Save this image');
}
}
});
Where img.attribs.src contains the url source path of the image.
Update
value of img.attribs.src
http://rack.1.mshcdn.com/assets/header_logo.v2-30574d105ad07318345ec8f1a85a3efa.png
https://github.com/nodeca/probe-image-size it does exactly you asked about, without heavy dependencies. Also, it downloads only necessary peace of files.
Example:
var probe = require('probe-image-size');
probe('http://example.com/image.jpg', function (err, result) {
console.log(result);
// => {
// width: xx,
// height: yy,
// type: 'jpg',
// mime: 'image/jpeg',
// wUnits: 'px',
// hUnits: 'px'
// }
});
Disclaimer: I am the author of this package.
What you want to do is to download the file first. The easiest way is to use request module. The cool thing is that both request and gm can use streams. The only thing you need to remember when working with streams and gm's identify commands (like size, format, etc) you need to set bufferStream option to true. More info here.
var gm = require('gm');
var request = require('request');
var url = "http://strabo.com/gallery/albums/wallpaper/foo_wallpaper.sized.jpg";
var stream = request(url);
gm(stream, './img.jpg').size({ bufferStream: true }, function (err, size) {
if (err) { throw err; }
console.log(size);
});
You could also download file on disk (using request as well) an then use gm as normal.
I've used this library to perform the operation successfully.
You need the image-size NPM, this work fine at my end hope work at your
var sizeOf = require('image-size');
sizeOf('/images/'+adsImage, function (err, dimensions) {
var imgwidth= dimensions.width;
var imgheight= dimensions.height;
console.log(imgheight +" = = = = "+imgwidth)
if( imgwidth>200 && imgheight>200)
{
console.log('Save this image');
}
});

svg to png convertion with imagemagick in 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);

Resources