iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🌧️

Create Dynamic OGP Images with Cloudinary in Just 10 Minutes!

に公開

Introduction

Are you familiar with a service called Cloudinary?
Cloudinary is a cloud service for managing images, allowing you to easily store, edit, and deliver images.

By uploading a template image to Cloudinary to serve as the base for your dynamic OGP image and hitting a URL in a specific format, you can easily create dynamic OGP images.
In fact, Cloudinary is also used in the Zenn service, and Catnose-san introduced it on his personal blog as well!

https://catnose.me/notes/cloudinary-dynamic-ogp-image

It's so simple that you can literally create it in 10 minutes, so if you're having trouble creating dynamic OGP images, please give it a try!

Let's Build It Right Away

This guide assumes you have registered for Cloudinary and have at least one Cloud created.
https://cloudinary.com/users/login

1. Create a Template Image

First, prepare a template image for the static parts using a tool like Figma.

↓ Something like this (we'll make it so the dynamic title appears above the orange line)
OGP template image

Next, upload this template image to the Cloudinary Media Library.
When doing so, give the uploaded image a clear name (Public ID) like ogp_image.

2. Create the OGP URL Using the SDK Provided by Cloudinary

The final OGP Image URL will look something like this:
https://res.cloudinary.com/dpgixnkg1/image/upload/c_fit/co_rgb:626161,l_text:zen-maru-gothic.ttf_30:%E4%BB%99%E5%8F%B0%E3%81%AB%E8%A1%8C%E3%81%A3%E3%81%9F%E3%82%88/fl_layer_apply,g_west,x_50,y_-30/yajium_site_ogp

It follows the format below, and you need to use a specific format of string so that Cloudinary can process it accordingly.
https://res.cloudinary.com/<Cloud Name>/image/upload/<Action Group>/<Template Image Public ID>

First, install the Cloudinary JavaScript SDK, which handles the creation of the above URL nicely.

npm install @cloudinary/url-gen
# or
yarn add @cloudinary/url-gen
# or
pnpm add @cloudinary/url-gen

Next, create a file like cloudinary.ts and write a function to generate the URL.

cloudinary.ts
import { Cloudinary } from "@cloudinary/url-gen";

const cld = new Cloudinary({
  cloud: {
    cloudName: "dpgixnkg1", // Replace with your own Cloud Name
  },
});

In this way, you generate a new cloud object.
When doing so, make sure to write your own Cloud Name in cloudName.

You can find your Cloud Name on the image Dashboard,
Cloud Name on the Programmable Media Dashboard page

or from the Product Environment constantly displayed in the bottom left.
Cloud Name in Product Environment

Next, create the getOgpImageUrl function, which actually retrieves the OGP image URL.

cloudinary.ts
import { Cloudinary } from "@cloudinary/url-gen";
+ import { source } from "@cloudinary/url-gen/actions/overlay";
+ import { fit } from "@cloudinary/url-gen/actions/resize";
+ import { Position } from "@cloudinary/url-gen/qualifiers";
+ import { compass } from "@cloudinary/url-gen/qualifiers/gravity";
+ import { text } from "@cloudinary/url-gen/qualifiers/source";
+ import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";

const cld = new Cloudinary({
  cloud: {
    cloudName: "dpgixnkg1",
  },
});

+export const getOgpImageUrl = (title: string) => {
+ const ogpImage = cld.image("ogp_image"); // Write the Public ID of the template image uploaded to your Cloud
+ ogpImage
+   .resize(fit()) // fit: automatically wraps into multiple lines based on the maximum width of the title string
+   .overlay(
+     source(
+       text(title, new TextStyle("zen-maru-gothic.ttf", 30)).textColor( // Specify custom font file and text color
+         "#626161"
+       )
+     ).position(
+       new Position().gravity(compass("west")).offsetX(50).offsetY(-30) // Adjust the position where the title string is displayed
+     )
+   );

+ return ogpImage.toURL();
+};

This function will receive title as an argument. This title will be the string that is dynamically changed and displayed.

Let's look at the parts mentioned in the comments.

First, ogpImage is the variable pointing to the template image.
By executing methods like .resize() and .overlay() on it, the image is being processed.

In .overlay(), text is specified as the source, and the characters are being processed.
new TextStyle("zen-maru-gothic.ttf", 30) applies a custom font.

Since Cloudinary only has Sawarabi Gothic as the default Japanese font, you need to set up a custom font if you want to use others.
For the application method, please refer to the Using Custom Fonts section of the following article.
Font files can be downloaded from places like Google Fonts.

https://www.memory-lovers.blog/entry/2021/09/09/070000

Note that underscores ("_") cannot be used in the Public ID of font files.

The .position() part adjusts the position of the title string.
gravity(compass("west")) sets the initial position of the string. In this case, it's west, so the leftmost character of the string is aligned with the left edge of the image.

The "west" part allows for position adjustment in various directions as shown below:

declare type ICompassGravity =
  | "north"
  | "center"
  | "east"
  | "west"
  | "south"
  | "north_west"
  | "south_east"
  | "south_west"
  | "north_east";

Starting from this "west" state, I want to align the leftmost part of the string above the orange line of the template image, so I used .offsetX(50).offsetY(-30) to adjust the x and y coordinates.

For more details on text processing, the following is a helpful reference:
https://cloudinary.com/documentation/javascript_image_transformations#adding_text_and_image_overlays

By the way, you could generate the URL string directly without using this official SDK, but since you would then need to handle things like title encoding yourself, I used the SDK this time.

3. Embed the Created URL into the OGP Tags

Finally, embed the URL into the OGP tags, and you're done!

const ogpImageUrl = getOgpImageUrl(title);
---
<meta property="og:image" content="{ogpImageUrl}" />

↓ My site ended up looking like this:
Example of OGP image (in the case of yajium.day)

Conclusion

What did you think?
Personally, I felt it was easier to set up than vercel/og, which was great.

I hope you find this useful as one of your options when creating dynamic OGP images! 😃

GitHubで編集を提案

Discussion