ChatGPT, me and lightweight Hugo Image gallery

March 29, 2023
programming Python Hugo ChatGPT JavaScript Photography Website

As someone who has battled with programming, I know from my experience how difficult it can be to execute an idea as a program or a website from scratch. When I first started, finding and understanding all the documentation wasn’t easy. I often relied on other people’s scripts and solutions for everything, from basic HTML to complex CSS and JavaScript. How many questions must one ask/read to write a single line of code?

On top of that, finding time to learn and experiment with these different programming languages was tough to include in my daily schedule. Between work and other responsibilities, it seemed impossible to dedicate enough time to become proficient in all the necessary skills.

Nevertheless, fortunately, times have changed, and thankfully, tools are now available that can help even those with mostly superficial knowledge execute their ideas as working pieces of code. One such tool is large language models, which have made it possible to generate complex code, automate many tasks that were once time-consuming and difficult, and even provide a reasonable explanation and brainstorming with own code.

Recently, I wanted to create a gallery for my website using Hugo and JavaScript; lightweight with a nice lightbox effect but fully adjustable. However, I didn’t have the knowledge or experience to build it from scratch. That’s where ChatGPT came in - it helped me figure out the necessary steps to create the gallery and provided me with the code I needed to get started.

With the help of ChatGPT, I created a column- and row-based gallery for a Hugo-based website with a simple yet stylish lightbox. The gallery idea was borrowed from my portfolio gallery mfg92 hugo-shortcode-gallery ). However, some web mining was necessary to correct parts of the new row-based based gallery borrowed from ). Nevertheless, as an advocate for open source, I have shared both galleries on my GitHub for anyone who would like to use a simple and nice-looking gallery. I plan to add some extra features, such as thumbnail generation and a proper lazy loading mechanism.

The experience has taught me that even with limited programming knowledge, it’s possible to achieve great things with the help of tools like ChatGPT. Correct prompt usage is, however, a key to getting expected answers. I’m excited to see what other projects I can create with these resources and explore new ideas, maybe not effortlessly, but still. Creating those two galleries still took me 3 days of work. Using tools such as ChatGPT is like having a senior programmer/personal assistant around. You can always ask a question. But there is no judgment (I hope!).

My new galleries work only on Desktop browsers with a minimum screen width of 1000px (which can be changed in the shortcodes). The reason is that Lightbox on mobile devices is unnecessary, and images look better as a single column. The gallery shortcode requires providing the unique identifier of the gallery so Lightbox knows which gallery to iterate through. Some settings and the description of the parameters I include below can be changed. The gallery can also show the EXIF or any other list information per image, and I also had a code for generating an EXIF list from the pictures.

Regarding the images themselves, they come from various points in my photographic journey in the last two years, including a middle-of-Covid hike, my previous trip in Switzerland, my first wedding shoot in the USA, a spontaneous beach walk in La Jolla, night sky gazing in 2022, surfing with friends, and some of my favorite lab photos. Enjoy!

gallery_row.html ⬇️


 1{{<gallery_column folder="images1/" randomize=false uniqueID="1" scale=100% columns="3" gap=10 showAlt=true long_list="Swiss Alps, La Jolla Cliffs, Beach, Starry Night, Wedding day, Plasma, Surf, In the clouds, Snow1, Snow2" >}}
 4folder --> folder name that is present where *.md file is stored
 5randomize --> whether to randomize order of images
 6columns --> number of columns
 7uniqueID --> unique identifier of the gallery
 8height --> height of the gallery row
 9gap --> gap between images in the gallery
10showAlt --> whether to show image annotations in the gallery
11longList --> list of annotations seperated by comma (,). Can be image names or EXIF information
12scale --> scale of the lightbox preview
13usefile --> whether to use the file to load annotations
14filename --> path to the file to load annotations


 1{{<gallery_row folder="images2/" randomize=false uniqueID="2" height=230 gap=10 showAlt=true scale=100% usefile=true filename="/content/blog/post38/data/exif2.txt">}}
 4folder --> folder name that is present where *.md file is stored
 5randomize --> whether to randomize order of images
 6uniqueID --> unique identifier of the gallery
 7height --> height of the gallery row
 8gap --> gap between images in the gallery
 9showAlt --> whether to show image annotations in the gallery
10longList --> list of annotations seperated by comma (,). Can be image names or EXIF information
11scale --> scale of the lightbox preview
12usefile --> whether to use the file to load annotations (overrides longList)
13filename --> path to the file to load annotations
gallery_column.html ⬇️

To generate the file with EXIF data this script can be used: ⬇️
 1import piexif
 2import glob
 3from PIL import Image
 4import os
 6# Function to get EXIF data from an image file
 7def get_exif(file):
 8    img =
 9    exif_dict = piexif.load(['exif'])
10    return exif_dict
12# Specify the folder containing image files
13folder = 'folder/images2/*.jpg'
14files = sorted(glob.glob(folder))
16# List of metadata to retrieve
17metadata_location = ['Model', 'LensModel', 'ExposureTime', 'FNumber', 'ISOSpeedRatings', 'FocalLength', 'ApertureValue']
19# List to store EXIF strings for each image
20exif_str_list = []
22# Iterate over image files
23for file in files:
24    exif_dict = get_exif(file)
26    # Initialize variables to store metadata
27    Model, LensModel, ExposureTime, FNumber, ISOSpeedRatings, FocalLength = "", "", "", "", "", ""
29    # Iterate over EXIF tags
30    for lfn in exif_dict:
31        for tag in exif_dict[lfn]:
32            try:
33                metadata = piexif.TAGS[lfn][tag]["name"]
34                if metadata in metadata_location:
35                    tag = exif_dict[lfn][tag]
37                    if metadata == 'Model':
38                        Model = tag.decode()
39                    elif metadata == 'LensModel':
40                        LensModel = tag.decode()
41                    elif metadata == 'ISOSpeedRatings':
42                        ISOSpeedRatings = f'ISO {tag}'
43                    elif metadata == 'ExposureTime':
44                        ExposureTime = f'{tag[0]}/{tag[1]}s'
45                    elif metadata == 'FNumber':
46                        num, den = int(tag[0]), int(tag[1])
47                        FNumber = f'F/{num/den if num % den != 0 else num//den}'
48                    elif metadata == 'FocalLength':
49                        num, den = int(tag[0]), int(tag[1])
50                        FocalLength = f'{num//den}mm'
51            except KeyError:
52                pass
54    # Combine metadata into a single string
55    single_exif = f'{Model} + {LensModel} <br>{ExposureTime} {FNumber} {ISOSpeedRatings} @{FocalLength}'
56    exif_str_list.append(single_exif)
58# Save the list of EXIF strings to a file
59save_file = os.path.join(os.path.dirname(files[0]), 'exif.txt')
61# Write the EXIF strings to the file without brackets and single quotes
62with open(save_file, 'w') as f:
63    formatted_exif_str = ', '.join(exif_str_list)
64    f.write(formatted_exif_str)
66# Read the cleaned EXIF strings back from the file (optional)
67with open(save_file, 'r') as f:
68    cleaned_exif_str =
70print("Cleaned EXIF strings:", cleaned_exif_str)
75NIKON Z 6 + NIKKOR Z 24-70mm f/4 S <br>1/2500s F/14 ISO 160 @70mm, NIKON D750 + 24.0-70.0 mm f/2.8 <br>1/2500s F/5.6 ISO 250 @24mm, NIKON D750 + 24.0-70.0 mm f/2.8 <br>1/3200s F/9 ISO 200 @29mm

Was it useful?