Resize image in Hugo (v 0.32.x) in markdown - hugo

I am trying to resize an image in Hugo (not using HTML / CSS), which is apparently available in the v 0.32 update. Beneath the "Image Processing" heading at the link in the last sentence, the following "Resize" method is described:
Resize to the given dimension, {{ $logo.Resize "200x" }} will resize to 200 pixels wide and preserve the aspect ratio. Use {{ $logo.Resize "200x100" }} to control both height and width.
I'm having some trouble implementing this in my Hugo site. In particular, I am using a .md file, and am trying to add an image which is stored somewhere else in the site's source files.
For example, here's how I would add the (not-resized) image in the .md file:
![pdf image](../static/_media/images/pdf.png)
How could I add this same file, resized to 50x50 pixels, using the resize method in the v0.32 release?

Using my newer version of Hugo (v0.53) I had to adapt the answer by JoostS a bit:
Created a page bundle
Modified the shortcode to look like this at the start:
{{ $original := .Page.Resources.GetMatch (print "images/" (.Get 0) "*") }}

You can not use it like this (in markdown). Resizing only works on resources. A resource is a file in the resource directory or a file in a page bundle. To access resources in markdown you will have to use a shortcode.
Note that you can define the static dir as the resources directory. Once you do that, you can just use the static directory and write something like:
(.Site.Resources.GetMatch "_media/images/pdf.png").Resize "50x50"
However, you should access this through a shortcode, like Talves did. I simplified his code a little for extra readability:
{{< imgresize "_media/images/pdf.png" >}}
Calling this shortcode (layouts/shortcodes/imgresize.html):
{{ $image := (.Site.Resources.GetMatch (.Get 0)).Resize "50x50" }}
<img src="{{ $image.RelPermalink }}">

As of 2022, if all you need is displaying the image in a different size, maybe Hugo’s Built-in "figure" Shortcode would do?
{{< figure src="/media/spf13.jpg" title="Steve Francia" >}}

You will need to make sure you have included your images within the content of your page usually at the level of the page itself unless you reference them using the answer I link in the note below.
NOTE: You can access resources from an outside section as in this answer
Write a shortcode
layouts/shortcodes/imgresize.html
{{ $original := .Page.Resources.GetByPrefix (.Get 0) }}
{{ $options := .Get 1 }}
{{ .Scratch.Set "image" ($original.Resize $options) }}
{{ $image := .Scratch.Get "image" }}
<img src="{{ $image.RelPermalink }}" width="{{ $image.Width }}" height="{{ $image.Height }}">
[Alternative] Shortcode accessing resource under content/media section
{{ $imagename := (.Get 0) }}
{{ $options := .Get 1 }}
{{ with .Site.GetPage "section" "media" }}
{{ $original := .Resources.GetByPrefix $imagename }}
{{ with ($original.Resize $options) }}
<img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}">
{{ end }}
{{ end }}
Call the shortcode from within the markdown of the page.
{{< imgresize pdf "50x50" >}}
pdf refers to the image by its name prefix to get the resource.
Using a sub folder page to access the resources
In the next example shortcode you must have a page at the same level as your images. Include an index.md at the same level (example: content/media/logos/index.md)
add layouts/shortcodes/logo-resize.html
{{ $imagename := (.Get 0) }}
{{ $options := .Get 1 }}
{{ with .Site.GetPage "page" "media/logos/index.md" }}
{{ $original := .Resources.GetByPrefix $imagename }}
{{ with ($original.Resize $options) }}
<img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}">
{{ end }}
{{ end }}
Call the shortcode
{{< logo-resize pdf "50x50" >}}
GitHub Example

If you're using Page Bundles you can reference any file in the page's folder, whether or not it is declared in front matter:
.
|- This is the Page (a folder)
|- index.md
|- photo1.jpg
\- photo2.jpg
INside index.md
{{< imgresize photo1.jpg "350x350" "Alternate Text" >}}
The shortcode (same as #Talves but uses GetMatch and Fit, and includes alternate text for image.)
{{ $original := .Page.Resources.GetMatch (.Get 0) }}
{{ $options := .Get 1 }}
{{ .Scratch.Set "image" ($original.Fit $options) }}
{{ $image := .Scratch.Get "image" }}
{{ $title := .Get 2 }}
<img src="{{ $image.RelPermalink }}" width="{{ $image.Width }}" height="{{ $image.Height }}" alt="{{ $title }}">

UPDATE! There is a new and better way: render hooks!
Create a render hook
For images in the markdown, you can use a ‘render hook’. This is a file that describes/overrides how markdown images are handled. To use the above approach in the render hook you should create the following file:
/layouts/_default/_markup/render-image.html
… and put this logic inside:
{{ if (resources.GetMatch .Destination) }}
<img src="
{{ ((resources.GetMatch .Destination).Fit `600x600 jpg Smart q50`).RelPermalink | safeURL }}
" alt="{{ .Text }}" />
{{ end }}
Note that we use ‘.Destination’ for the source of the original image and ‘.Text’ for the alt text defined in the markdown. Once you added the render hook all images in your Hugo project can and will be resized.
More info can be found at Hugo Codex and in the official docs.

Related

How to check if .Inner is empty

I am trying to write a {{< gallery >}} shortcode that will either generate a gallery with all the images in a directory you define, the contents you define via .Inner, or simply all the image resources related to the page. Here are the forms I'm trying to support:
{{< gallery dir="/gallery/alaska/" />}} - specified directory
{{< gallery >}} {{< figure src="image1.jpg" >}} {{< /gallery >}} - specified inner content
{{< gallery >}} - use all the image resources
I can process the first two, but it is not clear to me how to determine if there nothing in the .Inner variable so I can process form 3 above. I would expect to do something like the following:
{{- with (.Get "dir") -}}
// do stuff with the specified directory (works fine)
{{- else -}}
{{- if .Inner }}
{{ .Inner }} // Always executes
{{- else -}}
// do stuff related to resources in this page
{{- end }}
{{- end }}
How do I detect the bare shortcode with no arguments nor inner content?
The key to making this work is to use an empty tag in the form of <tag/> so that there is inner content but it is empty.
This means the following code works if you use {{< gallery />}} as your shortcode:
{{ with (.Get "dir") }}
// do stuff with the directory
{{ else }}
{{ with .Inner }}
{{ . }}
{{ else }}
// do stuff related to this page
{{ end }}
{{ end }}

Get timestamp for page ressources in a Hugo page bundle

I'm building a small image gallery for my website, and would like it to be ordered by creation date. The gallery is build as a page bundle with the individual images stored in a subfolder. Is there any way to access the creation date of the files from within a template, like you would use .Date or .Lastmod for posts?
I'm looking for solutions that doesn't require encoding the date in the file name or setting parameters for each image in the front-matter.
<!-- need something here
| -->
{{ range sort (.Resources.ByType "image") [?] "desc"}}
{{ $image := .Fill "500x500 center" }}
{{ $imageName := replace (path.Base .Name) (path.Ext .Name) ""}}
<li>
<figure>
<a href="{{.RelPermalink}}">
<img src="{{$image.RelPermalink}}" alt="{{$imageName}}" width="{{$image.Width}}px" height="{{$image.Height}}px"/>
</a>
<figcaption>{{$imageName}}</figcaption>
</figure>
</li>
{{ end }}

Hugo v0.55.x Deprecation Errors - ".File.BaseFileName" on zero object

I've been experimenting with finding a fix for a new deprecation error that occurs with Hugo version 0.55.5:
.File.BaseFileName on zero object. Wrap it in if or with: {{ with .File }}{{ .BaseFileName }}{{ end }}
The two affected snippets of code in question:
{{ $header := print "_header." .Lang }}
{{ range where .Site.Pages "File.BaseFileName" $header }}
{{ .Content }}
{{else}}
{{ if .Site.GetPage "page" "_header.md" }}
{{(.Site.GetPage "page" "_header.md").Content}}
{{else}}
<a class="baselink" href="{{.Site.BaseURL}}">{{.Site.Title}}</a>
{{end}}
{{end}}
&& the footer:
{{ $footer := print "_footer." .Lang }}
{{ range where .Site.Pages "File.BaseFileName" $footer }}
{{ .Content }}
{{else}}
{{ if .Site.GetPage "page" "_footer.md" }}
{{(.Site.GetPage "page" "_footer.md").Content}}
{{end}}
{{end}}
I've been attempting different variations of wrapping those segments of code with {{ with .File }} as the error message suggests, but it isn't liking anything I've been coming up with. As an example, if I put that surrounding bit of code around the {{ range ... }} statement, I get the error: can't evaluate field Site in type source.File. If someone could assist in figuring out where {{ with .File }} should be placed, it would be greatly appreciated.
You get this error
can't evaluate field Site in type source.File
Because the context changes when inside with. To fix it, wrap your code in a {{ with .File }} as you mentioned.
Then everywhere you're using .Site, replace it with site.
Then make sure you're using Hugo version 0.53.0 or higher, so that the site keyword is available.

Hugo - Access .Pages from the context of the list template from within the context of the single template

The documentation for hugo says the the .Pages variable inside the context of the single page is blank and that the .Pages variable from the context of the list page is populated.
I want to access the .Pages variable from the list page INSIDE the context of the single page.
How do I do this?
Documentation is below:
Worked through the issue here is what I came up with. This snippet:
{{ $currentPage := . }}
{{ range .Site.Pages }}
{{ if .InSection $currentPage}}
{{ if .IsAncestor $currentPage }}
{{ else }}
<li>
<a class="nav-link active" href="{{.Permalink}}">{{.Title}}</a>
</li>
{{ end }}
{{ end }}
{{ end }}

Concatenate variable in Hugo

This snippet works wonderfully on Hugo:
{{ if and (or .IsPage .IsSection) .Site.Params.contentCommitsURL }}
{{ $File := .File }}
{{ $Site := .Site }}
{{with $File.Path }}
Link to API call
{{ end }}
{{ end }}
With,
[Params]
contentCommitsURL = https://api.github.com/repos/csitauthority/CSITauthority.github.io/commits?path=HUGO/content/
it is able to beautifully generate the following link
Link to API call
in the layout html file.
Problem Description
The URL is generated. Now I'm pulling hairs trying to figure out how to concatenate the commands { $Site.Params.contentCommitsURL }}{{ replace $File.Dir "\\" "/" }}{{ $File.LogicalName }} in a page variable such as {{ $url }}
For instance:
{{ $url := {{ $Site.Params.contentCommitsURL }}{{ replace $File.Dir "\\" "/" }}{{ $File.LogicalName }} }}
does not work
but the following does:
{{ $url := "https://api.github.com/repos/csitauthority/CSITauthority.github.io/commits?path=HUGO/content/post/vlan-101.md"}}
I want to be able to do something like this:
{{ $url := $Site.Params.contentCommitsURL + (replace $File.Dir "\\" "/") + $File.LogicalName }}
^Obviously, that doesn't work. I want to know what does.
On the Hugo discourse forum, someone hinted a solution and I was able to come up with the following.
{{ if and (or .IsPage .IsSection) .Site.Params.contentCommitsURL }}
{{ $File := .File }}
{{ $Site := .Site }}
{{with $File.Path }}
{{ $fileDir := replace $File.Dir "\\" "/"}}
{{ $url := $File.LogicalName | printf "%s%s" $fileDir | printf "%s%s" $Site.Params.contentCommitsURL }}
{{ $.Scratch.Set "url" $url }}
{{ end }}
{{ end }}
Where I want it to appear, I use the Scratch function like this:
{{ $url := $.Scratch.Get "url"}}
{{ range getJSON $url }}
<div style="display:inline-block; width:40px;"><a href="{{.author.html_url}}" target="_blank">
<img src="{{.author.avatar_url}}" alt="{{.author.login}}" text="{{.author.login}}" class="inline" width="40" height="40" style="height: 40px;height: 40px; vertical-align:middle; margin: 0 auto;"></a>
</div>
{{ end }}
The code is self-explanatory so I won't bother with a verbose description. Instead, I'd like to bring your focus on the implementation. You'll notice that the Scratch function has been used.
The hugo documentation says this:
Variables defined inside if conditionals and similar are not visible on the outside.
(see this issue)
It's a workaround that involves storing the value temporarily. here's more on scratch
Limitations
As of this moment, I feel this code is not complete. It works but, it shows the author based on commits. So multiple commits will generate the same author multiple times. I bring this limitation to your notice, to develop a creative solution. I'll update this answer when I get a satisfactory answer. Meanwhile, feel free to suggest.
here's my original answer on hugo discourse.

Resources