Pipe image output from Graphics Magic to response without base64 encoding - node.js

I have a Node server where, instead of storing cropped images, I want to crop them in response to an AJAX call, and send them to the client that way. I'm storing the information of what to crop and how to crop it in cookies and the body. On the server I crop it, encode it in base64, and send it back the user. Here is what my code looks like
res.set('Content-Type', 'image/jpeg');
gm(request(body.URL))
.crop(req.cookies[name+"Width"],req.cookies[name+"Height"],req.cookies[name+"X"],req.cookies[name+"Y"])
.stream(function streamOut (err, stdout, stderr) {
if (err) return next(err);
stdout.pipe(base64encode()).pipe(res);
stdout.on('error', next);
});
This works, but I don't like it. I was only able to get this to work by encoding it in base64, but on the client side this is seems slow to decode this to an image. I would rather just send an image directly, but I was unable to get this to work. Pipping the image without decoding it resulted in a gibberish response from the server. Is there a better way to do this? Or does the unsaved image have to be encoded in order to send?

I have no idea how you write node.js - it all looks like a bunch of dots and parentheses to me, but using what I know about the GraphicsMagick command line, I tried this and it does what I think you want - which is to write a JPEG encoded result on stdout:
// Send header "Content-type: image/jpeg"...
var gm = require('gm');
var input = 'input.jpg';
gm(input).resize(350).toBuffer('JPG',function (err, buffer) {
if (err) return handle(err);
process.stdout.write(buffer);
})
Update
Have you considered ruling out the AJAX aspects and just using a static src for your image that refers to the node script? As I said, I do not know node and Javascript but if I generate a thumbnail via a PHP script, I would add this into the HTML
<img src="/php/thumb.php"/>
So that just invokes a PHP script to generate an image. If you remove the /php/thumb.php and replace that with however you have named the node script I suggested above, it should tell you whether the problem is the AJAX or the GraphicsMagick aspects...

Related

How to render/generate image according to text/string in nodejs?

How can i generate an image of a string that has:
a size in px
embossed effect of the letters in the image
a font
a color
and other less important stuff that i think i can figure out once i achieve whats above like:
rotation of text
drop shadow
basically the user will send a request on how he wants his image to be.
but when i receive the request how should i make use of nodejs to render a png or a base64 url to send it back to the user. is there any libraries or way to achieve this.
i did some previous research and it doesn't seem like there is a frameworks that helps render text with a font and text style like emboss
You can try node canvas implementation: https://github.com/Automattic/node-canvas
Basically you can "draw" anything you want like if you'd be using browser js canvas, but some things may be different
Update - This will cover updating attributes of an image, not pulling text from image and updating that - you may need an image analysis library for that
Use the sharp library to manipulate the image as desired. https://github.com/lovell/sharp
http://sharp.dimens.io/en/stable/
A simple example that resizes (docs will show how to make the changes you want outside of this):
const request = require('request').defaults({ encoding: null });
request.get(imgUrl, params, function (err, res, body) {
sharp(body)
.resize(params.width, params.height)
.toFormat('jpeg')
.toBuffer()
.then((outputBuffer) => {
// outputBuffer contains JPEG image data no wider than params.width and no higher
// than params.height while maintaining quality of image.
let output = "data:" + res.headers["content-type"] + ";base64," + new Buffer(outputBuffer).toString('base64');
return output;
});
The output here will be the base64 image

Composite images in Graphicsmagick

I'm trying to request an image from an API and "paste" it on top of another image. In Photoshop, I would paste the image into a new layer and then merge the layers. I can accomplish this with Graphicsmagick using gm's composite().
gm().command("composite")
.in("path/to/topImg.png")
.in("path/to/bottomImg.png")
.toBuffer('PNG', function(err, buffer) {
if (!err) {return buffer;}
});
However, composite only takes file paths. So let's say I want to get the logo from http://www.google.com. I could save the image, use it in the code above, and then delete it. What I'm looking for is a way to accomplish this without having to save the image to disk first.
You can use URL directly as image path, without downloading and saving it
gm()
.command("composite")
.in("http://someurl...")
.in("http://someurl...")
.toBuffer('PNG', function(err, buffer) {
if (!err) {return buffer;}
});
But GraphicsMagick uses the HTTP support from libxml2, which does not currently support HTTPS. So if you want to download images over HTTPS you will need external program.

nodejs image manipulation with gm / imagemagick

I'm writing simple app that downloads JPEGs images from Flickr API, and then process them.
All I want to do, is to pick 4 random pixels from each image and save the HEX values.
Is it possible at all? I read a lot of graphicmagick documentation, but can't find a way to do this.
Whats the best way to decode JPEG and get this values? I tried a few plugins but neither can do this by default...
Take care!
https://npmjs.org/package/get-pixels seems nice for that:
var getPixels = require("get-pixels")
getPixels("lena.png", function(err, pixels) {
if(err) {
console.log("Bad image path")
return
}
console.log("got pixels", pixels.shape)
})

Store generated ImageMagick image to s3 without temp files

I am generating a PNG on the server side of a node.js application, using ImageMagick and the gm library for node.js (GraphicsMagick for node.js).
// start with a blank image
var gmImage = gm(100, 100, "#000000ff");
// Draw the stuff on the new blank image
When I'm finished drawing stuff using the gm library, I am storing that image to the file system:
gmImage.write(imagePath, function (err) {
...
});
I am now moving to s3. I want to skip this previous step and write the image direct to s3 without using a temporary file.
Is there a way to write the gmImage to a buffer or something?
Take a look at the stream section of the API: https://github.com/aheckmann/gm#streams
You should be able to pipe stdout into s3
var gmImage = gm(100, 100, "#000000ff");
gmImage.stream(function (err, stdout, stderr) {
stdout.pipe(s3Stream);
});

Storing a image in mongodb

I'm trying to store images in mongo after downloading it with request
here is my code which causes a corrupted image to be stored in db.
request('http://test.jpg', function (error, response, image) {
db.images.insert(
{
file_name: 'test.jpg',
image: new Buffer(image)
},
function(err){
//mongojs callback
}
);
});
Please note I am using mongojs module and storing the images in regular document as BinData type.
Also if I write the image to a file, read it then save the image to the database then there is no corruption. But I don't want to do this as is my intention to avoid the file-system altogether.
I'm pretty this has something to do with encoding or buffers but I don't know enough about these to solve my problem.
If you don't want to use a proper image storing solution like gridfs you could base64 encode your images.
How can you encode a string to Base64 in JavaScript?
That gives you a string that you can store in mongo.

Resources