More Haskell Diagrams: OpenGraph Images

Vehbi Sinan Tunalioglu - Aug 12 - - Dev Community

In this blog post, we are continuing to play with Haskell's diagrams library. We will write a literate Haskell program to generate an OpenGraph image.

Motivation

I am told that my Website pages should have OpenGraph images. So, I stopped worrying about not worrying about content, and I started worrying about not having an OpenGraph image.

So, let's do one.

Program

We will use the 3 Haskell packages for this Literate Haskell program like before: diagrams, diagrams-cairo and markdown-unlit.

Let's import a few modules.

import Diagrams.Backend.Cairo
import Diagrams.Prelude
import System.Environment (getArgs)
Enter fullscreen mode Exit fullscreen mode

Now, our entry point what will render an OpenGraph image with size 1200x630 and extension .png:

main :: IO ()
main = do
  dir <- head <$> getArgs
  logo <- loadLogo
  render dir "og.png" (og "thenegation.com" "by Vehbi Sinan Tunalioglu" logo)
  where
    render dpath fname = renderCairo (dpath <> "/" <> fname) (mkSizeSpec2D (Just 1200) (Just 630))
Enter fullscreen mode Exit fullscreen mode

This is how we will run our blog post:

runhaskell \
  -pgmLmarkdown-unlit \
  content/posts/2024-08-12_haskell-diagrams-og.lhs \
  static/assets/media/posts/haskell-diagrams-og
Enter fullscreen mode Exit fullscreen mode

Let's load my Website's logo image inside a Diagram B value. We are scaling the diagram to 24:

loadLogo :: IO (Diagram B)
loadLogo = do
  (Right img) <- loadImageEmb "./static/android-chrome-512x512.png"
  pure $ scaleUToX 24 $ image img
Enter fullscreen mode Exit fullscreen mode

Let's create a function to clip a given image in a circle. We will use the clipBy function to achieve this. Since our square image is scaled to 24, We are using a circle with a radius of 12:

mkAvatar :: Diagram B -> Diagram B
mkAvatar =
  clipBy (circle 12)
Enter fullscreen mode Exit fullscreen mode

Let's put some large text and then some smaller text under the avatar image to compose our OpenGraph image. Note that we use a canvas of 120x63, which is proportional to the OpenGraph image size of 1200x630 and play with arbitrary colours:

og :: String -> String -> Diagram B -> Diagram B
og txtB txtS img =
  logotype `atop` (rect 120 63 # fc (sRGB24read "#e4e4e7")  # lw none)
  where
    logotype =
      center $ vsep 9
        [ mkAvatar img
        , text txtB # bold # fontSizeL 6 # fc (sRGB24read "#09090b")
        , text txtS # fontSizeL 4.27 # fc (sRGB24read "#18181b")
        ]
Enter fullscreen mode Exit fullscreen mode

That's all! Let's see how PNG image looks like:

Wrap-Up

We have created an OpenGraph image for my Website. The next challange will be to add my blog post title and description to the image dynamically. I am not sure how to do that yet, especially with flowing text.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .