How to make one image from multiple images in node js - node.js

I want to make one image from multiples images in node js. I found the NPM package "spritesmith" for this. It combines the image and returns buffer representation of image, but I want to have more control over the final image. I want the input images to be display on specific position(pixel perfect) in final image, and also wants to downscale images. I have done some search, but found nothing about it. Can anyone please throw some possibillites for doing this thing. I want to combine about 10,000 images with 10 x 10 px for each image. What I'm planning is when a new image is uploaded by user, I want to add it to previously giant image.

Use the package Sharp.
images //your array of 10000 images
const emptyImage = await sharp({
create: {
width: 1000,
height: 1000,
channels: 3,
background: { r: 255, g: 255, b: 255 },
},
})
.composite(
images.map((image, index)=>({
input: image,
left: index%100,
top: parseInt(index/100),
width: 10,
height: 10,
}))
)
.toFormat('jpeg', { quality: 100 })
.toBuffer();

Related

Sharp NodeJS: How to add an overlay to an animated gif?

I'm trying to make a composition on an animated gif. The overlay appears only for a small instance. I suppose that's because it's being applied only on one frame/page.
So my question is, how do I apply the overlay to all the pages/frames in the gif with sharp? This is the code:
let image = await sharp(req.file.buffer, { animated: true, pages: -1 });
const metadata = await image.metadata();
await image
.composite([
{ input: logo, left: Math.floor(metadata.width * 0.1), top: Math.floor(metadata.height * 0.1) },
])
.toFile(filepath);
Thanks in advance!
Same issue here, fixed by using tile and gravity.
.composite([
{
input: logo,
tile: true, gravity: 'northwest'
}
])

Is it possible to create a tile 2x2 mosaic using Sharp Node?

Using Image Magick I was able to use montage to make this:
With this code:
montage -density 300 -tile 2x0 -geometry 150x150^ -gravity center -crop 150x150+0+0 -border 0 '.$img_array.' /var/www/html/uploads/output.jpg
I would like to know if this is possible too using Sharp, I saw the tile option but I don't understand how to use 4 different images together.
Thanks to the Author, I found this tricky solution.
Imagine you want a 2x2 mosaic with a fixed size of 400x400 pixels.
In the example below I have all my images into ./images/ folder. All 4 images are of fixed size 200x200 pixels.
You need also a background picture big enough to contain the mosaic. You can use for this any image and resize with Sharp as well.
const sharp = require('sharp');
sharp('./images/output4.jpg')
.resize(400, 400)
.toFile('bg.jpg', function(err) {
console.log("Something wrong",err)
});
Now that you have created the bg.jpg image you can run this JavaScript:
const sharp = require('sharp');
sharp('./images/bg.jpg') //here call the previous generated image
.composite([
{ input: './images/output1.jpg', gravity: 'northwest' },
{ input: './images/output2.jpg', gravity: 'northeast' },
{ input: './images/output3.jpg', gravity: 'southwest' },
{ input: './images/output4.jpg', gravity: 'southeast' },
])
.toFile('combined.jpg');
In the future will be easier with something like this (not yet implemented):
vips arrayjoin "./images/1.jpg ./images/2.jpg ./images/3.jpg ./images/4.jpg" out.jpg --across 2

FabricJS resizing groups and objects in them

I need to programmaticaly resize a group and it's contained elements on a fabric canvas.
By default, fabric applies scaling to objects. I can get around this easily enough by using the scalex & scaley to calculate the new height and width then I set them back to 1. This works fine for the group but I cant figure out how to set the new size for the objects contained in this group.
Eg. Before resize:
After resize:
My (typescript) code is like:
redraw() {
this.shapeGroup.set({
scaleX: 1,
scaleY: 1,
left: this.shape.origin.x,
top: this.shape.origin.y,
width: this.shape.extent.width + this.shape.line.lineWidth,
height: this.shape.extent.height + this.shape.line.lineWidth,
dirty: true
});
// const ac = this.shapeGroup.calcCoords();
this.shapeElement.set({
rx: this.shape.cornerRadius,
ry: this.shape.cornerRadius,
width: this.shape.extent.width,
height: this.shape.extent.height,
dirty: true
});
// this.shapeElement.setCoords(ac);
if (this.shape.text) {
this.textElement.set({
width: this.shapeElement.width - (this.cornerRadius * 2),
height: this.shapeElement.height - (this.cornerRadius * 2)
});
}
this.canvas.fabric.renderAll();
}
(this.shape is the underlying model of the object which is represented by 1 or more fabric objects in a group).
Has anyone done anything like this with success?
I used a similar code to resize the group items, so maybe this can lead you to a solution.
canvas.setActiveGroup(this.shapeGroup.setCoords());
var objs = canvas.getActiveGroup().getObjects();
for(i in objs){
objs[i].set({
...
});
}

Cloudinary.url is not working as expected

I'm wanting to convert an image url so it can include the transformation properties (I want to change the width and height). Here is an example of what I store in my database (the url Cloudinary gives us when we upload an image)
https://res.cloudinary.com/blah/image/upload/v15/orsdrkjfddaqjlwsk0t.jpg
I'm using node.js and the cloudinary library gives us the following method: cloudinary.url().
It does not seem to work when I pass the cloudinary image URL to it:
cloudinary.url('https://res.cloudinary.com/blah/image/upload/v15/orsdrkjfddaqjlwsk0t.jpg',
{ width: 100, height: 100 });
It will just return the original url, it won't add any transformation values to it?!
Note: I what I did to get it to work was strip orsdrkjfddaqjlwsk0t.jpg from the url & pass it to the cloudinary.url method. However if the image stored in my database is not one from cloudinary, stripping the nameofimage.jpg from the url won't work! Cloudinary will create a cloudinary URL for it WHICH does not exist.
You need to specify a crop mode for the width and height to take into effect. For example,
cloudinary.url('https://res.cloudinary.com/blah/image/upload/v15/orsdrkjfddaqjlwsk0t.jpg',
{ width: 100, height: 100, crop: "scale"});

Adding text over images in fabricjs

developing this app in which there several images on a canvas and i am using using fabricjs.
i want to add text overlaid on an image and then be able to remove it as well.
is a way to directly write over the image or do i have to create another layer and write onto it.
there is text related like
var text = new fabric.Text('hello world', { left: 100, top: 100 });
canvas.add(text);
the problem with the above approach is that if the image moves the text will not, so is it possible that the text could be written directly above the image?
any ideas of how this could be done? i revived several discussions where it's not as clear, how it could be done.
any pointers would be most appreciated.
This could be achieved by creating an image and a text object, then adding both the objects to a group and finally adding that group to the canvas.
Here's an example, showing that in action ...
var canvas = new fabric.Canvas('canvas');
// load image
fabric.Image.fromURL('https://i.imgur.com/Q6aZlme.jpg', function (img) {
img.scaleToWidth(100);
img.scaleToHeight(100);
// create text
var text = new fabric.Text('hello world', {
left: 10,
top: 5,
fontSize: 15,
fontFamily: 'Verdana',
fill: 'white'
});
// add image and text to a group
var group = new fabric.Group([img, text], {
left: 50,
top: 50,
});
// add the group to canvas
canvas.add(group);
});
canvas{border:1px solid #ccc}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.11/fabric.min.js"></script>
<canvas id="canvas" width="200" height="200"></canvas>
I am not quite clear of what exactly is your requirement.
Regardless of it, i have created a JS Fiddle for you.
https://jsfiddle.net/xpntggdo/9/
textBox=new fabric.Textbox("Enter Text",{
fontSize: 16,
fontFamily: 'Arial',
textAlign: 'left',
width: 180, // for 20 characters
top:arrowTop,
left:arrowLeft
});
canvas.add(textBox);
canvas.renderAll();
This might be of a little help at least. Comment on this answer and I will try to help you more on it if that is possible for me.

Resources