Resizing front matter images

Is there any way to resize images that are not included in a page bundle? Forestry suggest an interesting solution using .Resources.GetMatch that is close to what I need but requires all images be located in an ‘uploads’ directory. This makes managing large collections of images problematic.

It seems like Hugo might be able to handle this scenario, but the syntax eludes me.

If images are located as follows.

|── content
    └── posts
        └── 2019
            └── image1.jpg
            └── image2.jpg

What do I need to change in the following code to read and resize image1.jpg and image2.jpg?

{{ with .Params.image }}
    {{ $image := ($.Site.GetPage "section" "uploads").Resources.GetMatch (strings.TrimPrefix "/uploads/" . ) }}
    {{ $r := $image.Fill "200x200" }}
    <img src="{{ $r.RelPermalink }}">
{{ end }}

The front matter looks like this.

image: /posts/2019/image1.jpg
1 Like

Should anyone be interested in the future, I’ve managed to solve this with the following code:

{{ with .Params.image }}
    {{ with ($.Site.GetPage (path.Dir .)).Resources.GetMatch (path.Base .) }}
        {{ $r := .Resize "240x" }}
        <img src="{{ $r.RelPermalink }}">
    {{ end }}
{{ end }}

The only caveat being each image directory requires an index.md file inside it. With headless: true set inside the front matter (this is mentioned in the earlier linked Forestry solution.

2 Likes

In this scenario typically I pass the front matter img parameter as a string to create a resource. See:

1 Like

Ahh okay. How would I modify the code above to create it that way?

My bad. I actually misremembered what is the output of the fromString method. This is meant for text/html files not images. Sorry for that.

Also I looked into one of my older projects where I was creating a resource from a string and I was also using resources.Get. So what you posted above is more or less what I’ve also been doing.

No worries. It does seem odd to have to resort to hacks like headless: true when you’re just passing strings around, but at least I have a solution I’m happy with.

Not necessarily. There are 2 places in which images can reside: Page Bundles and the Assets directory, one can always fetch these images from the latter if Page Bundles are not desired.

I thought the assets directory was located within a theme directory? These are all content images, so that doesn’t seem like the correct place to put them. What if I later switch themes?

Regardless, I have a solution that works. I appreciate developer efforts so don’t want to debate whether Page Bundles are a sensible design or not. Forestry figured a hack, and I only need to copy a three-line file into a few hundred image directories to make the code happy.

No. The assets directory is independent from a theme. You may have one directly under the root of a Hugo project and at the same time your project’s theme may use another one.

Ahh, in that case I’ve misunderstood something.

What’s the trick to make resources.Get look at the assets directory in the root of a project rather than defaulting to the one inside the theme?

There is no trick and no default to the asset directory under a theme. You simply fetch the image.

For example for an image under assets/main.jpg one would simply need to do:

{{- $path := resources.Get "/main.jpg" -}}
{{- $thumb := ($path.Resize "400x").RelPermalink }}
<img src="{{ $thumb }}">

If you wish for your images to live in different directories you simply construct the PATH as needed.

The bonus of this approach is that anything residing under the assetDir does not get published unless outputted as a resource with its .Permalink or .RelPermalink

Sidenote:
I’ve seen GitHub issues and topics here with users complaining because high resolution images within Page Bundles are published by Hugo, but if these images were placed under /assets/ they wouldn’t.

Also the assets directory can be configured with a different name by specifying an assetDir parameter in a project’s config.

Oh wow. That’s the code I was looking for.

Confusingly, if an image does not exist, the error reported suggests resources.Get was only ever looking in the theme/assets directory, which was throwing me. For example.

error calling Get: stat [root]/themes/[theme name]/assets/main.jpg: no such file or directory

But if the file is found it works perfectly. My current config.toml has the following set:

assetDir = "content"

Now I can read files direct from the content folder without the headless: true hack. Thank you.

One additional comment. The call to resources.Get was preventing rebuilding if a given image was missing or referenced incorrectly. So I wrapped it with a basic file check.

{{ if fileExists . }}
    {{ with resources.Get . }}
        {{ $thumb := (.Resize "400x").RelPermalink }}
        <img src="{{ $thumb }}">
    {{ end }}
{{ end }}
2 Likes

Are you saying that if assetsDir = "content" you can place your assets throughout the content folder (in a page bundle, for instance) and thatresources.Get` will work (i’m guessing if you specify the correct path)?

on another note:

you can upvote for Forestry to include folders in their media browser.

1 Like

Yes. That is what I’ve done and it appears to work just fine.

I’m not using Page Bundles though, just loose .markdown files in the posts directory. Images are located as specified at the top of this thread and an image is referenced in the front matter. Full code:

{{ with .Params.image }}
    {{ if fileExists . }}
        {{ with resources.Get . }}
            {{ $thumb := (.Resize "400x").RelPermalink }}
            <img src="{{ $thumb }}">
        {{ end }}
    {{ end }}
{{ end }}