Is it possible to use org mode to publish an image gallery?

Viewed 117

Based on the org mode publishing tutorial it is unclear whether this is possible, or even supported. Additionally, none of the example personal websites mention multiple images as part of a typical blog setup. Thanks in advance for your time!

* Note: the image gallery is sometimes referred to as an image carousel depending on the source

1 Answers

My gallery method has 3 main components: Special blocks, a filter function, and an external CSS/JS gallery library.

Special blocks: I use links to images with a description, but any method should be possible to make work. Keep in mind we're going to be working with the HTML that org produces from this markup. You might prefer [[file:images/test.png]] or [[file:images/full.png][file:images/thumb.png]] depending on your final desired output. I also chose to keep my markup simple because browsers without JS or even CSS can fallback to the thumbnails and image links.

 #+BEGIN_gallery
 [[file:images/test.png][test]]
 [[file:images/psx.jpg][playstation]]
 [[file:images/IMG_1047.jpg][telephone]]
 [[file:images/pants.png][pants]]
 #+END_gallery

Filter function: This filters arguments before 'org-html-special-block handles them. This one modifies only 'gallery' special block arguments. Other special blocks have their args passed on directly. We're using the advice feature to filter the arguments.

My actual filter function is a bit more complex because it calls out to imagemagick's convert to optimize, strip, and resize files before copying them into the publishing directory. The one shown here is just focused on the markup filtering.

(defun my-html-gallery-links (args)
  (let ((special-block (nth 0 args))
        (contents (nth 1 args))
        (info (nth 2 args)))
    (if (string= (org-element-property :type special-block) "gallery")
      (progn
        (with-temp-buffer
          (insert contents)
          (goto-char (point-min))
          (while (re-search-forward "<a href=\"file://\\(.*\\)\">" (point-max) t)
                 (setq image_filename (match-string 1))
                 (replace-match
                   (concat
                     "<a href=\""
                     image_filename
                     ;; Set class for javascript lightbox library
                     "\" class=\"imagelightbox\">"))
                 (backward-char 1)
                 ;; Swap text link description for the image thumbnail
                 ;; move text description to alt attribute
                 (re-search-forward ">\\(.*\\)\</a>" (point-max) t)
                 (replace-match 
                   (concat
                     "><img src=\""
                     "thumbs/" 
                     image_filename
                     "\" alt=\""
                     (match-string 1)
                     "\" /></a>")))
          (setq contents
                (buffer-substring-no-properties (point-min) (point-max))))
        (list special-block contents info))
      args)))
(advice-add 'org-html-special-block :filter-args #'my-html-gallery-links)

Before the filter function I got links like:

<a href="images/IMG_1047.jpg">telephone</a>

After the filter function the links are:

<a href="images/IMG_1047.jpg"><img src="thumbs/IMG_1047.jpg" alt="telephone" /></a>

A CSS or Javascript library: You can use very simple ones like lightbox/cssbox (CSS only) or go crazy. I settled on Osvaldas' ImageLightbox because of the features, and it works with simple markup.

To integrate it into my publishing run I have a static component to handle the js/css (as described in the tutorial). Then I set :html-head in the notes component.

:html-head "<link rel=\"stylesheet\" href=\"/res/org.css\" type=\"text/css\" />
<script type=\"text/javascript\" src=\"/res/jquery-3.6.1.js\"></script>
<script type=\"text/javascript\" src=\"/res/imagelightbox.js\"></script>
<script type=\"text/javascript\"> $(function () { $( 'a.imagelightbox' ).imageLightbox(); }); </script>"

The gallery I'm using isn't carousel style, but the markup can be tweaked to suit examples like the one you linked. Just surround the images with suitable HTML elements and appropriate class/id attributes.

A screenshot of my gallery (simple lightbox with back/forward navigation)

Related