#182 Build an OpenGraph image generator

09/08/2024
image generation ferrum
Transcript
Hello friends. So recently I saw this very interesting question on Reddit. What do you use for generating open graph images automatically? So among the answers, that was the GR magic that lets you, uh, draw images using Ruby. And actually I made a real nice episode number 91 on this topic where you can, uh, programmatically overlay images, overlay text in different positions and generate an image. And the final result looked more or less like this. This was actually used as an open graph image for, uh, sports games. Uh, another answer was using the Jim Grove. That is, uh, headless Chrome, API that uses, uh, puppet and node in the background. And my suggestion was, uh, to use the Ferrum that is just like Grover, but it doesn't have the additional dependencies of Node and Puppet, it is just a Ruby headless Chrome, API. They've also different, uh, paid, uh, options recommended as thumb smith.com and actually generating OpenGraph images automatically is, uh, interesting business niche. There are quite lot of businesses around this. So for example, there is tiny app where you can, uh, put in A URL and it'll take a screenshot of this URL and put it, uh, above a nice background. There is HTML, uh, to css image.com where you can, uh, use, uh, HTML to draw images and then, uh, it'll generate the images and uh, it actually has like quite a few different price and tiers. So they pay you, you pay for how many images you want to generate. There is also, uh, thumb smith.com, og image, uh, dot org where you can, uh, again, here's a nice example. You would, uh, share a link to do hunt.com and, uh, if it doesn't have an open graph image, it would look just like this so it doesn't look really clickable, doesn't look nice. But if it does have an open graph image that it look really nice. And what we're going to do, we're going to build our own open graph image generator. Because we're developers, we don't want to pay for an external tool to generate images automatically. So here in this example application, we are going to have a list of Ruby conferences where there is a name allocation start date, and A URL. And based on just this data, we're going to do generate this kind of images where we're going to have a nice background, um, screenshot of the website, the name of the conference, the location, the date, and this is going to be an image. And they're going to attach this image to each event and displayed as an open draft image so that it is visible, uh, when sharing this link, uh, a link to this, uh, event online. And, uh, let's start doing it. So first of all, we're going to just have a basic application where we have, uh, an events model with name, location, study, and URLI actually seeded the events using this script. You will be able to see it in the seed file of, uh, the repository. You should have access to the repository at cogo slash episode 182. Okay. And, uh, here is our basic application. So let's start by adding the gem ome that they're going to use to, uh, take screenshots of, uh, these URLs and, uh, store them in each event. Object. So, um, I will say, uh, bundle add ome and it's going to install, uh, this Gem Rum and Firm has, uh, a screenshots, uh, API. So we are going to visit a page and take a screenshot of the page. So, uh, let's try doing this. I'm going to actually generate a job for this. So I'll say rails, generate a job, uh, uh, event, uh, URL to, uh, image, they're going to open this job event URL to image job. We're going to pass the event object. We will, uh, have your L equals event url. They're going to start, uh, uh, rum. So we'll say rum browser new. Now let's go to this. Uh, go to, we'll be going to the URL. They're going to take the screenshot and we'll ensure that they create their browser. And, uh, they're going to store the screenshot, uh, somewhere. Let's store it. For example, in our assets, uh, at the beginning, I will store it, uh, in app slash assets images slash uh, uh, u rl parameterize, uh, jpg. So JPGs are more lightweight than PNGs, and, uh, JPGs are enough for our use case. They're going to also say quality will be 40%, but voltage it is 75. And we will also mention the format will be, uh, JPG. Okay, let's, uh, try taking a screenshot. So I will open it in the, uh, console. Run this job in the console, uh, event to image shop, uh, dot, perform. Now, event. First it is supposed to, uh, take the event URL, open the firm browser, visit the URL, uh, take a screenshot and store it in our assets. So let's go to our assets. And you see, uh, this image has been, uh, generated. Looks, uh, quite okay. Uh, we can also, uh, try this in the URL and see if, uh, it looks the same. Let's, uh, visit this URL. Yes. And, uh, it looks more or less, uh, the same, same. But you see this, uh, ruby gem was not, uh, uh, generated in our image. Maybe it needs some more time to load. So, um, we will add a command web. We'll, before taking the screenshot, we'll say browser.network, wait until idle and additionally sleep, uh, tool, uh, to ensure that, uh, all the images, everything is uh, loaded. So I will load and run the job once again. Uh, yeah, the autocomplete was not, uh, correct, wait for idle. Okay, let's reload. This time, it'll take a bit longer. Let's have a look at the image. And you see now it generated the image already, uh, with this, uh, ruby jam. So the image generation worked, uh, well, okay, we have generated an image and stored it in our assets, but we want to attach this image to our event. So, uh, instead of, uh, this approach, we're going to attach the image to our event. I will say, uh, um, TMP equals temp file. New, uh, we're going to take the screenshot, um, to this path. So path will be, uh, tmp do path, and now we'll say event. Do, uh, image do attach, uh, this file, the tmp, uh, path. Okay. And, uh, to be able to attach an image to an event, we need to add active storage. So in our event, we don't have, uh, possible to, to attach images yet. So I will install active storage, uh, storage bin rails, active storage install. Let's run the migration rails to be migrate, uh, has one attached image. Okay, so now this job should attach an image. So a screenshot to the event, uh, let's see if it works. I'll run the console event equals event first, uh, event to image, job dot, perform now event. And this time it's not, uh, store the image in assets. It should attach the image to the event. So let's say event image attached. Yes, it is attached. So we can try display in the image, uh, in our local host. Uh, I will go to the event partial. And somewhere here I will say, uh, um, image tag. Event image cannot, uh, resolve image into UL. Uh, maybe some events don't have image attached. So I will say if, uh, event image attached. Okay. And, uh, I will additionally say if event image dot representable, it's additional nice check to have to be sure that, uh, this, uh, element can be viewed. And I will additionally say with, uh, 500, for example. Okay. And now we have taken a screenshot of, uh, this webpage and, uh, we displayed, uh, uh, on the web event. So it looks really nice. Uh, we can do the same with all the other events. We can, uh, add, run this job automatically when the event is created. So for example, in the event model, you could have an, uh, uh, yeah, a callback to run this job or to complete this, helping me a lot with this. So it would look more like this. You would, uh, generate a screenshot of the webpage of the event whenever an event is, uh, created. Let's go further and, uh, not just generate a screenshot, but also make it look, uh, nice. Uh, add some, uh, text around it, add a background. So this is going to be a bit harder. Instead of just taking a screenshot, we are going to also generate our own h tm l around it and take a screenshot. Uh, well actually, yeah, we're going to use, not use the browser to screenshot just like this of a UL. We're going to input our own HTML into the browser and take a screenshot of our own HTML. So let's generate our own H TM L. Let's, uh, try this an an event. Let's take this event and I will generate my own HTML in the slash og. So let's create our own, uh, uh, template. Inside events, uh, og html and here will have equals event title, for example. Now we need a route for this. So I will go to our roots and say, events two, member two get og. And okay, the route exists. The title is undefined. So going to events controller, I will set event for the open graph for also. And, uh, yeah, event doesn't have title, event has name. Okay, so this is going to be our starting template based on which we're going to make something nice looking like this. I'm actually not going to build the cs s out, uh, on my own. I'm going to copy it. Just I will also use not our application H tml, uh, template. I'm going to create a separate, uh, layout template. So let's name it minimal html dot erb. I will remove, uh, everything I don't need. And, uh, this og HTML ERB will, uh, render the template. Uh, that is minimal dev OG render, uh, layout minimal. I think like this. Let's, uh, double check with folks. I will put something in this layout. Yes, I'm rendering this layout. And now I'm going to style this layout. Now I'm just going to copy some styles. So here is the minimal layout styling where we have a background, we center everything in the center, and we rotate all the content a bit so that it looks, uh, rotated by like a few degrees like this. Let's, uh, save and refresh. And you see we have this background and we have the text, uh, that is slightly rotated. And we're also going to update our OGH, TM L with, uh, some CSS. Let's, uh, see how it looks. Okay, so it can look more, less like this. You see, we have the title that we under here, uh, the event name. We have the event location, the event, uh, start date, and an image. Now you see I render not just the image tag event image, but I have all this, uh, hack stuff around. You will see why. Let's first try rendering without all the second stuff, just event image. And you see it folks, as before. Now, we are going to try to take a screenshot not only of uh, this, uh, URL, but a screenshot of this page that we have, uh, uh, generated and, uh, wrapped on our own. So step one is, uh, taking a screenshot of, uh, the URL. Step two is going to be take a screenshot of this page that we created on our own. So, uh, let's create another job. Uh, rails generate, uh, job, let's name it. Uh, let's see how the previous job was named event URL to image. So, uh, event open graph event, OG image. Let's open event OG image job. And it's going to be quite similar to the previous job. Let's copy everything. But there are going to be a few slide differences. So we're not going to go to A URL, but instead we're going to input our own HTML that we're going to have. Uh, here we're going to input this HTML. So, uh, instead of go to URL, we will, uh, say, uh, frame equals browser frames first frame do, uh, content equals uh, HTML and H. TM L is going to be some h tml that we render in line here. So HTML will be application controller, do render, and here it'll be template events, OG layout, minimal. And uh, do we have event here? Yeah, we would need to have at event. So let's set, uh, at event equals, uh, event. Okay, so we are going to render this H TM L that we have created on our own. Uh, we are going to put it inside the browser. We're going to wait for all the images to load. And then we're going to take a screenshot and store it in the event OG image, not just the event image. So let's add an OG image, uh, to the event. So first we generate an image of the URL, and then they generate an open graph image based on this additional sty into which we wrapped our screenshot. Uh, let's see. Let's try run this command and see if it works. Event equals event. First, let's have a look at the event. It is the same van event image attached. Yes, we have an image. So let's run the event OG image, uh, job A form now on the event. Okay, and define the name for nil class. Um, so event is not defined. Maybe we need to pass a science event equals event. Let's reload. Okay, let's try viewing the event, uh, OG image. So just as we have the image, we'll have OG image. Now let's go to the list of events. And yes, here we have the screenshot and we have the open graph image. And you see the image was not, uh, rendered. It wasn't rendered because, uh, I, uh, was rendered in plain HTML in our job and it didn't find the correct path to the event image. So to actually make it fo uh, using rum programmatically, I would need to have the base URL, uh, rails, plot path, event image. This way it would, uh, work. Let's drive. Once again, I will reload and run the job once again. Now I will refresh. And, uh, you see, uh, the image has been loaded well this time. So, uh, we managed to take a screenshot and we managed to take, uh, a screenshot of the H TM l uh, that we have generated on our own. Looks quite nice. Now, open graph images have a specific size. I think it is 1,200 pixels wide and 630 pixels high as recommended. So we are going to specify it here. I'm going to say the, uh, browser dot resize with and height here and here. And now I'm going to run this, uh, jobs for all the other URLs, or at least for a couple of them. I'm going to actually run this job after this job. So whenever I attach the image, uh, I'm going to run the open craft image generator performed later for the event. So one job is going to trigger another job. Let's try running this for another conference. Let's take, uh, Euro for example. It's event number four. Uh, event equals event find four. We are going to run this event UL to image shop for now event. So it is going to take a screenshot of, uh, the URL, and then it's going to take, uh, it's going to render the screenshot inside our own layout here, the one that we have styled, and take a screenshot of it and attach to the event. Let's run this. It can take a bit longer. I'm, uh, putting sleep in, uh, both cases and in both cases I'm waiting for, uh, the network to load everything so that all the images are loaded nicely. And let's refresh this event. Okay, it has an, uh, attached screenshot, but it looks like it did not, uh, manage to run out the job yet. It seems to be still running. So let's wait a bit. Yes, and you see it has generated the second image. Now we want to display this images, uh, in the open graph. So if we go to inspect, we should have a meta tag that is open graph image, and uh, this image. So I'm going to go to our application layout and here I will say equals yield head. And inside events slash show, I will, uh, put, uh, a block to yield the meta tags. So, um, what is the content for? I will have content for head do, and here I will have, uh, equals tag dot meta, and I will have, uh, property named the OG image, and the content will be a URL to this, uh, second, uh, image that I have generated. So, uh, what is the path to this image? Uh, let's see. I think we can use Rails blob, not path, but URL. This is important. It has to been absolute URL event, OG image, um, and to close the braces. And, let's see, once again, I'm going to refresh. I'm going to go to the head. And here I have meta property, OG image. Let's open this URL. And here I have this, uh, open graph image. So fantastic, just from having a few, uh, lines like name of event, location, start date, and your l It took a screenshot, uh, of the URL. We wrapped it inside the, our own template and, uh, generated an OpenGraph image for this event. We can do it the same for all the other events. And, uh, each event when visiting it, uh, and sharing the in, uh, app like Twitter or LinkedIn will have a nice open graph image attached to it. So that's basically it. This is, uh, I think a really nice use case for how you can use the ome headless browser. See you in the next one.
4
Join the conversation
Sign in to leave comments and save lessons to your watchlist.
We collect your email address, name and username to create your account. We do not share your email address with anyone else.