This is also related to the bot, I have described here. Since then, I have found another api that allows reading message history and counting likes on each.
So, I've had an idea to select the best one for each month.
It is not that interesting: you just have to use the telegram npm package and follow the docs.
The channel I'm talking about is called "Postcards from Finland", therefore I wanted to make those best-liked images look like postcards.
Programmatically, of course.
This is my type of fun.
There are several npm packages that provide image manipulation possibilities, but the majority of them require 3rd party stuff like Imagemagick, which I didn't want to use - my code should be running on a free tier Oracle VM, so I wanted to keep things as simple as possible.
So, I came across The JavaScript Image Manipulation Program, Jimp. Just check out their logo!
I wanted to achieve a Polaroid-like look, put a postal stamp on and do some writing. The end result should be like that:
/6/1.jpg
This, obviously, is not something from the channel, this is my middle finger after I've hurt myself a while ago. Anyway.
First, we'll load an image and get it's dimensions:
const image = await Jimp.read('output.jpg');
const { width, height } = image.bitmap;
Now let's add borders. Either I'm dumb, or there's no built-in way of doing it, so I'm gonna create white rectangles and slap them onto the image:
const border = 20;
const borderH = new Jimp({ width, height: border, color: 0xffffffff });
image.composite(borderH, 0, 0);
const borderV = new Jimp({ width: border, height, color: 0xffffffff });
image.composite(borderV, width - border, 0);
image.composite(borderV, 0, 0);
const borderB = new Jimp({ width, height: border * 4, color: 0xffffffff });
image.composite(borderB, 0, height - border * 4);
This is for the vertical image - the bottom border is 4 times wider.
Next, I'll add a black overlay, to make the image look more printed.
const overlay = new Jimp({
width,
height: height - border * 3,
color: 0x000000ff,
});
overlay.opacity(0.1);
image.composite(overlay, 0, 0);
Adding a stamp is pretty much the same - you load another image and then place it using the "image.composite" method.
So, the only thing that is missing is the text. It should be easy, right?
Right?
So, I've found some ".ttf" font which I liked and downloaded it. First issue I've encountered is that Jimp docs are outdated and "Jimp.loadFont" doesn't seem to exist, it should be imported separately.
The next issue was this:
const font = await loadFont('.my_font.ttf');
has failed with an error, that I honestly did not even understand. But it was clear, that Jimp is unhappy with this font format. I've looked into it's GitHub and realized that it uses ".fnt" fonts.
At this point I've tried using different libs, like "node-canvas", which, according to the documentation, should be able to use my font.
It did not. After making several efforts, I've realized I'm not the only one who has a problem and there's an open GitHub issue.
So, I've decided to try and convert the font.
Surprisingly, there are different tools for that and some of them just don't work. This one does.
A ".fnt" is actually just a bitmap, so this tool has generated an image
/6/2.png
and a file that describes which part of this image corresponds to which letter
/6/3.png
Now, we're one step closer!
const font = await loadFont('.my_font.fnt');
This works as expected.
There's one more thing though: some (well, most of them actually) images are landscape, so the text should go vertical. I have spent more time than I'm willing to admit looking for a way to do that. I have even decided to ask wise people on StackOverflow.
But than I've had an idea both dumb and brilliant: rotate an image, print text, rotate back.
image.rotate(90);
image.print({
font,
x: border,
y: width - 50,
text: 'tome text goes here',
});
image.rotate(-90);
That's it, the code is on Github.
I've learned how to mutilatemanipulate images in node.js, and surely had some specific fun while doing it.