Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 861
jamjam Avatar asked Jul 22 '12 10:07

jamjam


2 Answers

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.

like image 106
Split Your Infinity Avatar answered Oct 31 '22 13:10

Split Your Infinity


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.

like image 3
Stennie Avatar answered Oct 31 '22 14:10

Stennie