GitHub: HugoPhotoSwipe
A tool for creating PhotoSwipe galleries in Hugo
For this site, I wanted to create photo galleries using PhotoSwipe by Dmitry Semenov, because I really like the user interface that it gives. The PhotoSwipe viewer looks very nice on mobile and desktop browsers and has built-in support for captions. If you haven’t seen any galleries with PhotoSwipe yet, you can take a moment to browse through some galleries of mine.
I’m using Hugo by Steve Francia for this site and creating a PhotoSwipe gallery in Hugo was not immediately trivial. PhotoSwipe requires predefined image sizes and obviously I didn’t want to set this by hand for every gallery. Moreover, I wanted to serve responsive images for the mobile version of the site and use best practices for SEO. Search Engine Optimization. For images to be properly identified by search engines, it’s good to have descriptive filenames, alt-text, and captions. Finally, I wanted to create nice thumbnails automatically using SmartCrop and make it easy to add or change photos in the gallery.
This problem has bugged some other people too. The first solution I could find was by Tom Helmer Hansen who wrote a blog post about how he tackled this problem using shortcodes. This seems like a workable solution, but didn’t go quite as far as I’d like because image sizes still needed to be set by hand. A recent Bash script written by Björn Pohl goes a bit further, but still requires more manual intervention than I would like. Finally, there’s this GitHub repository by Ziosi Brunetto Marco, which contains a Go script for generating the Markdown, similar to the Bash script by Björn Pohl but with detection of image sizes. Unfortunately, none of these solutions gave the automatic workflow I would like.
So I made HugoPhotoSwipe, a command line application for creating and updating PhotoSwipe galleries in Hugo. HugoPhotoSwipe is also available from PyPI. The idea is to have a directory of photos for each gallery and a corresponding description file where captions of the photos can be defined. HugoPhotoSwipe then takes care of creating responsive image sizes and thumbnails, as well as a markdown file which can be processed by Hugo. If any photos or captions are changed or added, HugoPhotoSwipe recognizes this and updates the gallery and resized photos accordingly.
Below a more detailed description follows about how
HugoPhotoSwipe works. A shorter description with step-by-step usage
instructions can be found in the GitHub Readme. A
complete walkthrough is
also available.
After you’ve installed HugoPhotoSwipe, a
hps
command line program should be available. There are four basic
commands to this program: init
, new
, update
, and clean
. The
init
command creates a hugophotoswipe.yml
configuration file in the
current directory.
This is the main configuration file for HugoPhotoSwipe and is used to define
general settings that hold for all albums, such as the output directory and
the dimensions of the images that will be created. With the new
command
you can create a new album. An album for HugoPhotoSwipe is basically a
directory with an album.yml
file and a subdirectory with the original
photos for the gallery.
The album.yml
file contains the title of the album, the captions of the
photos, which image is the cover image, etc. This file also keeps track of
hashes for the photo files so that changes can be detected. The update
command is the one you’ll probably use most, since it generates the markdown
and the resized photos and thumbnails. Finally, the clean
command removes
the output created by the update
command, in case you want to regenerate
the output. So, the intended setup for HugoPhotoSwipe is to have a source
directory, with the following structure:
/path/to/source/directory
├── bologna
│ ├── album.yml
│ └── photos
│ ├── photo_1.jpg
│ ├── photo_2.jpg
│ └── photo_3.jpg
├── chicago
│ ├── album.yml
│ └── photos
│ ├── photo_a.jpg
│ ├── photo_b.jpg
│ └── photo_c.jpg
└── hugophotoswipe.yml
In this case we have two albums, each with three photos. After running
HugoPhotoSwipe using the hps update
command, the output directory will
look similar to this:
/path/to/output/directory
├── bologna
│ ├── coverimage.jpg
│ ├── large
│ │ ├── photo_1_1066x1600.jpg
│ │ ├── photo_2_1600x1066.jpg
│ │ └── photo_3_1066x1600.jpg
│ ├── small
│ │ ├── photo_1_533x800.jpg
│ │ ├── photo_2_800x533.jpg
│ │ └── photo_3_533x800.jpg
│ └── thumb
│ ├── photo_1_256x256.jpg
│ ├── photo_2_256x256.jpg
│ └── photo_3_256x256.jpg
└── chicago
├── coverimage.jpg
├── large
│ ├── photo_a_1066x1600.jpg
│ ├── photo_b_1066x1600.jpg
│ └── photo_c_1066x1600.jpg
├── small
│ ├── photo_a_534x800.jpg
│ ├── photo_b_533x800.jpg
│ └── photo_c_534x799.jpg
└── thumb
├── photo_a_256x256.jpg
├── photo_b_256x256.jpg
└── photo_c_256x256.jpg
As you can see, resized versions and square thumbnails are created for each
photo. At the same time, the original album.yml
file is updated to
incorporate new photos that have been added. For instance, it hashes all the
original photos and stores these hashes in the album.yml
file, in order to
detect changed photos later. Finally, the Markdown files are created in the
markdown_dir
defined in the hugophotoswipe.yml
file, so that Hugo can
parse these into HTML files. These files contain
shortcodes
A shortcode is like a template which takes named variables.
like this:
{{< photo href="/photos/bologna/large/photo_1_1337x1600.jpg"
largeDim="1337x1600"
smallUrl="/photos/bologna/small/photo_1_535x800.jpg"
smallDim="535x800"
alt="Example Alt Text"
thumbSize="256x256"
thumbUrl="/photos/bologna/thumb/photo_1_256x256.jpg"
caption="Example Caption"
copyright="Example Copyright" >}}
Note how the urls to the photos all start with /photos/
. This is defined
in the url_prefix
setting of the hugophotoswipe.yml
file and should be
used to ensure the urls point to the actual files on your site. Next, a user
of HugoPhotoSwipe would define a shortcode in their Hugo configuration which
uses the variables provided in the Markdown to generate the HTML for the image
in the way that PhotoSwipe expects it. The shortcodes that HugoPhotoSwipe
requires are provided in the
documentation.
The documentation also contains the Javascript needed for using PhotoSwipe.
Finally, there are some minor features of HugoPhotoSwipe that I’d like to highlight here:
By default, HugoPhotoSwipe uses the Python version of SmartCrop to create the square thumbnails and the cover images. I’ve noticed that the original Javascript version can give slightly nicer results in some cases. Therefore, it is possible to switch to the Javascript CLI of SmartCrop in the
hugophotoswipe.yml
file. Simply setuse_smartcrop_js
toTrue
and add the path tosmartcrop-cli
in thesmartcrop_js_path
field.HugoPhotoSwipe allows you to set some options to the Pillow
save
command if you’re using the JPG output format. You can set the JPG quality, whether or not to optimize the JPG and whether or not to use progressive JPGs. See the documentation of these features here. I especially like the ability to set progressive JPGs, since this helps with optimizing the delivery of the images.You can specify additional fields in the
properties
field of thealbum.yml
file. For instance, in thealbum.yml
you can have:properties: country: U.S.A. camera: Samsung NX-300M
These properties will show up in the front matter of the generated Markdown file, as follows:
+++ ... country = U.S.A. camera = Samsung NX-300M ... +++
Since version 0.0.6, HugoPhotoSwipe can detect if an image has the rotation stored in an EXIF tag. This way you don’t have to worry about rotating your images correctly before running HugoPhotoSwipe.
That’s it! I hope you find HugoPhotoSwipe useful in your workflow. If you encounter any problems or have any questions please feel free to open an issue on the GitHub page.