Posts preview

Add post preview for OpenGraph cards

Table of Contents

What is imagemagick

Imagemagick is a ffmpeg of the image world. You can do a lot of fun things with it. For example you can take a picture, cut corners on it, place it on top of another image, add some text and get final result. So it is looks like a good tool for making previews from code.

Basic idea of this process

I want to hook a process of rendering post. Since this function called on each run of publishing and for each post it is a good idea to cache resulting images. I gonna simply check presence of preview image and use it as guard for running image generation. After that I gonna extract #+TITLE and #+DESCRIPTION properties from Org file. Each Org file I have, has next header:

#+TITLE: Posts preview
#+DATE: <2024-06-28 Fri>
#+DESCRIPTION: Add post preview for OpenGraph cards
#+TAGS: @blogging @org-mode @elisp @imagemagick

So I with all these data I can generate my previews with simple script:

 #!/bin/bash
 magick $4/with_profile.png \
     \( -size 850x150 \-background none -font Roboto-Regular -fill '#FEFEFE' label:"$1" -trim -gravity center -extent 850x150 \) \
     -gravity northeast -geometry +50+75 -composite /tmp/text_main.png
 magick /tmp/text_main.png \( -size 1100x300 -background none -font Roboto-Regular -pointsize 50 -fill '#FFFFFF' pango:"$2" -trim -gravity center -extent 1100x300 \) -gravity east -geometry +40+140 -composite "$3"
 #

Integrate into build

As I already mention I gonna skip file generation when file already here. Here is the whole function. Pretty simple. Just prepare pathes, check some dependencies, create pathes and execute script which calls imagemagick.

(defun my/render-preview (file-name title description)
  (let* ((has-imagemagick (executable-find "magick"))
         (full-file-path (file-truename(format "%s%s/resources/images/preview/%s.png" script-directory my/blog-src-path file-name )))
         (file-dir (file-name-directory full-file-path))
         (has-dir (file-directory-p file-dir))
         (has-file (file-exists-p full-file-path))
         (path-to-script-root (format "%shelpers" script-directory))
         (path-to-script (format "%s/og_image_gen.sh" path-to-script-root)))
    (if (and has-imagemagick
             (and description (not (string= description ""))))
        (progn
          (when (not has-file)
            (progn
              (when (not has-dir)
                (make-directory file-dir t))
              (shell-command (format "bash '%s' '%s' '%s' '%s' '%s'" path-to-script title description full-file-path path-to-script-root))
              )
            ))
      (message "Imagemagick is not installed. Preview generation skipped.")
      )))

And here is the part of my/template function related to OpenGraph meta tags.

(defun my/template (contents info)

  (let* ((title-str (org-export-data (plist-get info :title) info))
         (description-str (org-export-data (plist-get info :description) info))
         (file-path-str (org-export-data (plist-get info :input-file) info))
         (base-directory-str (org-export-data (plist-get info :base-directory) info))
         (file-name-str (file-relative-name file-path-str (format "%s/%s" script-directory base-directory-str)))
         (img-link-str (format "%s/resources/images/preview/%s.png" my/url file-name-str))

    (my/render-preview file-name-str title-str description-str)

    (set-text-properties 0 (length title-str) nil title-str)
    (set-text-properties 0 (length description-str) nil description-str)
    (set-text-properties 0 (length img-link-str) nil img-link-str)
...
              ;; OG block
              (meta ((name . "description") (content .  ,description-str)))
              (meta ((name . "og:description") (content . ,description-str)))
              (meta ((name . "twitter:description") (content . ,description-str)))

              (meta ((name . "og:image") (content . ,img-link-str)))
              (meta ((name . "twitter:image") (content . ,img-link-str)))

              (meta ((name . "og:title") (content . ,title-str)))
              (meta ((name . "twitter:title") (content . ,title-str)))

              (meta ((name . "twitter:card") (content . "summary_large_image")))

You can check whole function in previous post Improve code blocks.

Whats next?

Tags

Show tags, show posts by tag. Blog index and tags automation

Post series

Dunno how, but I'll figure out something.

Adopt/fix htmlize.el

I want to highlight code during publishing step.

Show more meta on posts index page.

Creation date, preview, tags, whatever. Blog index and tags automation