# Generating Article Thumbnails

> Published  Jun 06 2021, last updated Jun 06 2021  
> By Ryan Fleck <hello@this-site> and written without LLMs!  
> Original post at <https://ryanfleck.ca/2021/generating-article-thumbnails/>  
> An article of astonishing quality and insight. Happy Hacking!


I've always wanted to, rather than provide the same boring 'article' or 'node'
thumbnails, write a script to crawl my content and generate unique thumbnails
for each article. This morning, that's exactly what I did. The current script can
be viewed at [/generate_thumbnails.py](https://github.com/RyanFleck/ryanfleck.ca/blob/master/generate_thumbnails.py)

<!-- more -->

`generate_thumbnails`, for every page with a markdown file, will generate and
save a picture that looks like this:

<div class="child-image-borders">

![Sample thumbnail](/pics/HC12-ASM.md.png)

</div>

This is fairly easy to integrate into the header of each content page with _Hugo_.

We'll write thumbnails to `/assets/thumbnails/<article content path>.png`

In your `head.html` partial, prepare a path to the photo if the photo exists.

```go-html-template
<!-- If the article is an actual file, generate a thumbnail for it. -->
{{ $thumbnail := printf "%sr.png" .Site.BaseURL }}
{{ with .File }}
  {{ $picture := (path.Join "assets" "thumbnails" (print .Path ".png"))}}
  {{ if (and .Path $picture (fileExists $picture)) }}
    {{ $image := resources.Get (path.Join "thumbnails" (print .Path ".png")) }}
    {{ if $image }}
      {{ $thumbnail = $image.Permalink }}
    {{ end }}
  {{ end }}
{{ end }}
```

From here, all we need to do is write a _Python_ script to walk through our
filesystem, load the titles from the text files, and write the images.

I'll use [Pillow](https://pillow.readthedocs.io/en/stable/index.html) to create
a new image and paste in the calligraphic 'R' that I use as a logo.

From `PIL`, we'll need these libraries imported:

```py
import os
from PIL import Image, ImageDraw, ImageFont, ImageFilter
```

Next, walk through the `content` directory, find all the markdown files, and
save them into an array called `files`. I'll skip this step here, so check the
[source code](https://github.com/RyanFleck/ryanfleck.ca/blob/master/generate_thumbnails.py)
if you would like an example.

```py
files = get_content_files()
image_r = Image.open('static/r.png').resize((200, 200))

for file in files:

    # Get title
    title = ""
    with open(os.path.join(cwd, 'content', file), 'r', encoding='utf-8') as read_obj:
        # Read all lines in the file one by one
        for line in read_obj:
            if line and 'title' in line and line.startswith('title:'):
                title = line[8:len(line)-2]
                break

    print(f"Generating image for page '{title}'")

    # Split title into lines.
    title_split = title.split(" ")
    n = 25
    title_chunks = []
    working_chunk = ""
    for word in title_split:
        working_chunk = working_chunk + " " + word
        if len(working_chunk) > n or ':' in word:
            title_chunks.append(str(working_chunk))
            working_chunk = ""

    title_chunks.append(str(working_chunk))
```

At this point, we've gather the path and title of each article.

We can create and begin drawing an image.

```py
    image = Image.new('RGB', (1200, 630), (255,255,255))
    draw = ImageDraw.Draw(image)
    font=ImageFont.truetype("arial.ttf", 72)
    for chunk in range(len(title_chunks)):
        draw.text((40, 100+(chunk*80)), title_chunks[chunk], fill=(0, 0, 0), font=font)
    draw.text((770, 510), "ryanfleck.ca", fill=(83, 83, 221), font=font)
```

Let's prepare to save the image, ensuring that the directory we'd like to save
it in exists, or else we'll get an error when we try to save the photo.

```py
    image_file_path = str(os.path.join(dir_thumbnails, file + ".png"))
    image_file_directory = os.path.dirname(image_file_path)
    print(f"Saving to {image_file_path} in directory {image_file_directory}")
    if not os.path.exists(image_file_directory):
        os.makedirs(image_file_directory)
```

Finally, add the 'R' and save the image to the assets folder.

```py
    image.paste(image_r, (40, 400))
    filtered = image.filter(ImageFilter.SHARPEN)
    filtered.save(image_file_path)
```

...and that's it! In your header, you can now use the `$thumbnail` variable
in your meta to provide web crawlers with a link to your content thumbnail:

```html
<meta property="og:image" content="{{ $thumbnail }}" />
<meta property="twitter:image" content="{{ $thumbnail }}" />
```

Hopefully, after reading this, you'll be able to use the _Pillow_ library to
create personalized thumbnails for all your own content.

_Thanks for reading!_



> Thank you for reading!  
> Find more content at <https://ryanfleck.ca/>  
> Source page: <https://ryanfleck.ca/2021/generating-article-thumbnails/>  
> Site index: [llms.txt](https://ryanfleck.ca/llms.txt)