Skip to content

Commit

Permalink
tpl/images: Add images.QR function
Browse files Browse the repository at this point in the history
Closes #13205
  • Loading branch information
jmooring authored and bep committed Jan 6, 2025
1 parent 5d2cbee commit 4ea94c4
Show file tree
Hide file tree
Showing 10 changed files with 495 additions and 28 deletions.
31 changes: 17 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ Build the extended edition:
```text
CGO_ENABLED=1 go install -tags extended github.com/gohugoio/hugo@latest
```

## Star History

[![Star History Chart](https://api.star-history.com/svg?repos=gohugoio/hugo&type=Timeline)](https://star-history.com/#gohugoio/hugo&Timeline)
Expand Down Expand Up @@ -154,7 +155,7 @@ github.com/bep/clocks="v0.5.0"
github.com/bep/debounce="v1.2.0"
github.com/bep/gitmap="v1.6.0"
github.com/bep/goat="v0.5.0"
github.com/bep/godartsass/v2="v2.3.0"
github.com/bep/godartsass/v2="v2.3.2"
github.com/bep/golibsass="v1.2.0"
github.com/bep/gowebp="v0.3.0"
github.com/bep/imagemeta="v0.8.3"
Expand Down Expand Up @@ -189,7 +190,7 @@ github.com/gohugoio/locales="v0.14.0"
github.com/gohugoio/localescompressed="v1.0.1"
github.com/google/go-cmp="v0.6.0"
github.com/gorilla/websocket="v1.5.3"
github.com/hairyhenderson/go-codeowners="v0.6.1"
github.com/hairyhenderson/go-codeowners="v0.7.0"
github.com/hashicorp/golang-lru/v2="v2.0.7"
github.com/invopop/yaml="v0.2.0"
github.com/jdkato/prose="v1.2.1"
Expand Down Expand Up @@ -218,30 +219,32 @@ github.com/russross/blackfriday/v2="v2.1.0"
github.com/sass/dart-sass/compiler="1.81.0"
github.com/sass/dart-sass/implementation="1.81.0"
github.com/sass/dart-sass/protocol="3.1.0"
github.com/sass/libsass="3.6.6"
github.com/spf13/afero="v1.11.0"
github.com/spf13/cast="v1.7.0"
github.com/spf13/cast="v1.7.1"
github.com/spf13/cobra="v1.8.1"
github.com/spf13/fsync="v0.10.1"
github.com/spf13/pflag="v1.0.5"
github.com/tdewolff/minify/v2="v2.21.1"
github.com/tdewolff/parse/v2="v2.7.18"
github.com/tetratelabs/wazero="v1.8.1"
github.com/tdewolff/minify/v2="v2.20.37"
github.com/tdewolff/parse/v2="v2.7.15"
github.com/tetratelabs/wazero="v1.8.2"
github.com/webmproject/libwebp="v1.3.2"
github.com/yuin/goldmark-emoji="v1.0.4"
github.com/yuin/goldmark="v1.7.8"
go.uber.org/automaxprocs="v1.5.3"
golang.org/x/crypto="v0.29.0"
golang.org/x/crypto="v0.31.0"
golang.org/x/exp="v0.0.0-20221031165847-c99f073a8326"
golang.org/x/image="v0.22.0"
golang.org/x/mod="v0.22.0"
golang.org/x/net="v0.31.0"
golang.org/x/sync="v0.9.0"
golang.org/x/sys="v0.27.0"
golang.org/x/text="v0.20.0"
golang.org/x/tools="v0.27.0"
google.golang.org/protobuf="v1.35.1"
golang.org/x/net="v0.33.0"
golang.org/x/sync="v0.10.0"
golang.org/x/sys="v0.28.0"
golang.org/x/text="v0.21.0"
golang.org/x/tools="v0.28.0"
google.golang.org/protobuf="v1.35.2"
gopkg.in/yaml.v2="v2.4.0"
gopkg.in/yaml.v3="v3.0.1"
howett.net/plist="v1.0.0"
rsc.io/qr="v0.2.0"
software.sslmate.com/src/go-pkcs12="v0.2.0"
```
</details>
102 changes: 101 additions & 1 deletion docs/content/en/content-management/shortcodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ Hugo renders this to:
</details>
```

The details shortcode accepts these named arguments:
The `details` shortcode accepts these named arguments:

summary
: (`string`) The content of the child `summary` element rendered from Markdown to HTML. Default is `Details`.
Expand Down Expand Up @@ -333,6 +333,106 @@ Access nested values by [chaining] the [identifiers]:
{{</* param my.nested.param */>}}
```

### qr

{{% note %}}
To override Hugo's embedded `qr` shortcode, copy the [source code] to a file with the same name in the layouts/shortcodes directory.

[source code]: {{% eturl qr %}}
{{% /note %}}

The `qr` shortcode encodes the given text into a [QR code] using the specified options and renders the resulting image.

[QR code]: https://en.wikipedia.org/wiki/QR_code

Use the self-closing syntax to pass the text as an argument:

```text
{{</* qr text="https://gohugo.io" /*/>}}
```

Or insert the text between the opening and closing tags:

```text
{{</* qr */>}}
https://gohugo.io
{{</* /qr */>}}
```

Both of the above produce this image:

{{< qr text="https://gohugo.io" class="qrcode" />}}

To create a QR code for a phone number:

```text
{{</* qr text="tel:+12065550101" /*/>}}
```

{{< qr text="tel:+12065550101" class="qrcode" />}}

To create a QR code containing contact information in the [vCard] format:

[vCard]: https://en.wikipedia.org/wiki/VCard

```text
{{</* qr level="low" scale=2 alt="QR code of vCard for John Smith" */>}}
BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8:Smith;John;R.;Dr.;PhD
FN;CHARSET=UTF-8:Dr. John R. Smith, PhD.
ORG;CHARSET=UTF-8:ABC Widgets
TITLE;CHARSET=UTF-8:Vice President Engineering
TEL;TYPE=WORK:+12065550101
EMAIL;TYPE=WORK:jsmith@example.org
END:VCARD
{{</* /qr */>}}
```

{{< qr level="low" scale=2 alt="QR code of vCard for John Smith" class="qrcode" >}}
BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8:Smith;John;R.;Dr.;PhD
FN;CHARSET=UTF-8:Dr. John R. Smith, PhD.
ORG;CHARSET=UTF-8:ABC Widgets
TITLE;CHARSET=UTF-8:Vice President Engineering
TEL;TYPE=WORK:+12065550101
EMAIL;TYPE=WORK:jsmith@example.org
END:VCARD
{{< /qr >}}

Internally this shortcode calls the `images.QR` function. Please read the [related documentation] for implementation details and guidance.

[related documentation]: /functions/images/qr/

The `qr` shortcode accepts these named arguments:

text
: (`string`) The text to encode, falling back to the text between the opening and closing shortcode tags.

level
: (`string`) The error correction level to use when encoding the text, one of `low`, `medium`, `quartile`, or `high`. Default is `medium`.

scale
: (`int`) The number of image pixels per QR code module. Must be greater than or equal to 2. Default is `4`.

targetDir
: (`string`) The subdirectory within the [`publishDir`] where Hugo will place the generated image.

[`publishDir`]: /getting-started/configuration/#publishdir

alt
: (`string`) The `alt` attribute of the `img` element.

class
: (`string`) The `class` attribute of the `img` element.

id
: (`string`) The `id` attribute of the `img` element.

title
: (`string`) The `title` attribute of the `img` element.

### ref

{{% note %}}
Expand Down
115 changes: 115 additions & 0 deletions docs/content/en/functions/images/QR.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
title: images.QR
description: Encodes the given text into a QR code using the specified options, returning an image resource.
keywords: []
action:
aliases: []
related: []
returnType: images.ImageResource
signatures: ['images.QR OPTIONS']
toc: true
math: true
---

{{< new-in 0.141.0 >}}

The `images.QR` function encodes the given text into a [QR code] using the specified options, returning an image resource. The size of the generated image depends on three factors:

- Data length: Longer text necessitates a larger image to accommodate the increased information density.
- Error correction level: Higher error correction levels enhance the QR code's resistance to damage, but this typically results in a slightly larger image size to maintain readability.
- Pixels per module: The number of image pixels assigned to each individual module (the smallest unit of the QR code) directly impacts the overall image size. A higher pixel count per module leads to a larger, higher-resolution image.

Although the default option values are sufficient for most applications, you should test the rendered QR code both on-screen and in print.

[QR code]: https://en.wikipedia.org/wiki/QR_code

## Options

text
: (`string`) The text to encode.

level
: (`string`) The error correction level to use when encoding the text, one of `low`, `medium`, `quartile`, or `high`. Default is `medium`.

Error correction level|Redundancy
:--|:--|:--
low|20%
medium|38%
quartile|55%
high|65%

scale
: (`int`) The number of image pixels per QR code module. Must be greater than or equal to `2`. Default is `4`.

targetDir
: (`string`) The subdirectory within the [`publishDir`] where Hugo will place the generated image. Use Unix-style slashes (`/`) to separarate path segments. If empty or not provided, the image is placed directly in the `publishDir` root. Hugo automatically creates the necessary subdirectories if they don't exist.

[`publishDir`]: /getting-started/configuration/#publishdir

## Examples

To create a QR code using the default values for `level` and `scale`:

```go-html-template
{{ $opts := dict "text" "https://gohugo.io" }}
{{ with images.QR $opts }}
<img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}" alt="">
{{ end }}
```

{{< qr text="https://gohugo.io" class="qrcode" />}}

Specify `level`, `scale`, and `targetDir` as needed to achieve the desired result:

```go-html-template
{{ $opts := dict
"text" "https://gohugo.io"
"level" "high"
"scale" 3
"targetDir" "codes"
}}
{{ with images.QR $opts }}
<img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}" alt="">
{{ end }}
```

{{< qr text="https://gohugo.io" level="high" scale=3 targetDir="codes" class="qrcode" />}}

## Scale

As you decrease the size of a QR code, the maximum distance at which it can be reliably scanned by a device also decreases.

In the example above, we set the `scale` to `2`, resulting in a QR code where each module consists of 2x2 pixels. While this might be sufficient for on-screen display, it's likely to be problematic when printed at 600 dpi.

\[ \frac{2\:px}{module} \times \frac{1\:inch}{600\:px} \times \frac{25.4\:mm}{1\:inch} = \frac{0.085\:mm}{module} \]

This module size is half of the commonly recommended minimum of 0.170 mm.\
If the QR code will be printed, use the default `scale` value of `4` pixels per module.

Avoid using Hugo's image processing methods to resize QR codes. Resizing can introduce blurring due to anti-aliasing when a QR code module occupies a fractional number of pixels.

{{% note %}}
Always test the rendered QR code both on-screen and in print.
{{% /note %}}

## Shortcode

Call the `qr` shortcode to insert a QR code into your content.

Use the self-closing syntax to pass the text as an argument:

```text
{{</* qr text="https://gohugo.io" /*/>}}
```

Or insert the text between the opening and closing tags:

```text
{{</* qr */>}}
https://gohugo.io
{{</* /qr */>}}
```

The `qr` shortcode accepts several arguments including `level` and `scale`. See the [related documentation] for details.

[related documentation]: /content-management/shortcodes/#qr
9 changes: 5 additions & 4 deletions docs/data/embedded_template_urls.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@
'google_analytics' = 'google_analytics.html'
'opengraph' = 'opengraph.html'
'pagination' = 'pagination.html'
'schema' = 'schema.html'
'twitter_cards' = 'twitter_cards.html'

'robots' = '_default/robots.txt'
'rss' = '_default/rss.xml'
'schema' = 'schema.html'
'sitemap' = '_default/sitemap.xml'
'sitemapindex' = '_default/sitemapindex.xml'
'twitter_cards' = 'twitter_cards.html'

# Render hooks
'render-codeblock-goat' = '_default/_markup/render-codeblock-goat.html'
'render-image' = '_default/_markup/render-image.html'
'render-link' = '_default/_markup/render-link.html'
'render-codeblock-goat' = '_default/_markup/render-codeblock-goat.html'
'render-table' = '_default/_markup/render-table.html'

# Shortcodes
'comment' = 'shortcodes/comment.html'
Expand All @@ -31,6 +31,7 @@
'highlight' = 'shortcodes/highlight.html'
'instagram' = 'shortcodes/instagram.html'
'param' = 'shortcodes/param.html'
'qr' = 'shortcodes/qr.html'
'ref' = 'shortcodes/ref.html'
'relref' = 'shortcodes/relref.html'
'twitter' = 'shortcodes/twitter.html'
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ require (
google.golang.org/protobuf v1.35.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
howett.net/plist v1.0.0 // indirect
rsc.io/qr v0.2.0 // indirect
software.sslmate.com/src/go-pkcs12 v0.2.0 // indirect
)

Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,8 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=
rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
software.sslmate.com/src/go-pkcs12 v0.2.0 h1:nlFkj7bTysH6VkC4fGphtjXRbezREPgrHuJG20hBGPE=
Expand Down
Loading

0 comments on commit 4ea94c4

Please sign in to comment.